
/*
    Software License

    Copyright (C) 2021-05-24  Xoronos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

/*
    Liabilities

    The software is provided "AS IS" without any warranty of any kind, either expressed,
    implied, or statutory, including, but not limited to, any warranty that the software
    will conform to specifications, any implied warranties of merchantability, fitness
    for a particular purpose, and freedom from infringement, and any warranty that the
    documentation will conform to the software, or any warranty that the software will
    be error free.

    In no event shall Xoronos be liable for any damages, including, but not limited to,
    direct, indirect, special or consequential damages, arising out of, resulting from,
    or in any way connected with this software, whether or not based upon warranty,
    contract, tort, or otherwise, whether or not injury was sustained by persons or
    property or otherwise, and whether or not loss was sustained from, or arose out of
    the results of, or use of, the software or services provided hereunder.

    To request the provided software under a different license you can contact us at
    support@xoronos.com
*/

#include "xrn_crypto.h"
#include <pthread.h>

int xrn_estimate_steg_block_length_bytes( uint64_t envelop_length, uint8_t folding_en, uint64_t * capacity
 )
{

    XPRINT_DEB(  );

    uint64_t available_capacity;
    char tabs[5];

    if ( ( xlog.not_fp == NULL ) || ( capacity == NULL ) ) {
        XPRINT_ERR( 1152, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( ( folding_en != 0 ) && ( folding_en != 1 ) ) {
        XPRINT_ERR( 1176, XERR_IO_MSG );
        return XERR_IO;
    }

    available_capacity = envelop_length;

    // if the capacity is too small
    if ( ( available_capacity / 4 ) < sizeof( header_block_t ) + sizeof( uint32_t ) ) {
        XPRINT_ERR( 1151, XERR_IO_MSG );
        return XERR_IO;
    }

    //       actual capacity, block header,            crc32
    available_capacity = ( available_capacity / 4 ) - sizeof( header_block_t ) - sizeof( uint32_t );

    if ( available_capacity <= 256 ) {
        XPRINT_ERR( 783, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( folding_en == 0 ) {
        available_capacity = available_capacity - 256;
    }

    strncpy( tabs, "   ", 4 );
    if ( xlog.not_en ) {
        fprintf( xlog.not_fp,
                 "{\n%s\"message_type\" : \"steganography_block_length\",\n%s\"byte_capacity\" : %lu }\n",
                 tabs, tabs, available_capacity );
    }

    *capacity = available_capacity;

    if ( folding_en == 1 ) {
        if ( available_capacity <= 512 ) {
            XPRINT_WAR( XWAR_STEG_CAPACITY_MSG, XWAR_STEG_CAPACITY );
            return ( int ) XWAR_STEG_CAPACITY;
        }

    }

    return XSUCCESS;

}

int xrn_make_steg_raw_bytes( uint8_t * encoded_bytes, uint64_t encoded_bytes_length,
                             uint8_t * in_envelop_bytes, uint64_t in_envelop_length,
                             uint8_t * out_envelop_bytes, uint64_t out_envelop_length
 )
{
    XPRINT_DEB(  );

    uint8_t c;
    uint64_t index;
    uint32_t tmp32, out32;
    int j;
    uint64_t index_in_envelop, index_out_envelop, index_encoded;
    int final_ret;

    final_ret = XSUCCESS;

    index_in_envelop = 0;
    index_out_envelop = 0;
    index_encoded = 0;

    if ( ( encoded_bytes == NULL ) || ( in_envelop_bytes == NULL ) || ( out_envelop_bytes == NULL ) ) {
        XPRINT_ERR( 630, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // Read and write the specified length of data from the input file to the output file
    while ( ( index_encoded < encoded_bytes_length ) && ( index_in_envelop < in_envelop_length - 4 )
            && ( index_out_envelop < out_envelop_length - 4 ) ) {

        c = encoded_bytes[index_encoded];
        index_encoded++;

        // write buffer with steganography

        for ( j = 0; j < 4; j++ ) {
            ( ( uint8_t * ) & tmp32 )[j] = in_envelop_bytes[index_in_envelop];
            index_in_envelop++;
        }

        out32 = steg_encode( c, tmp32 );

        if ( out_envelop_length < index_out_envelop + 4 ) {
            XPRINT_ERR( 633, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            out_envelop_bytes[index_out_envelop] = ( ( uint8_t * ) & out32 )[j];
            index_out_envelop++;
        }

    }

    for ( index = index_in_envelop; index < in_envelop_length; index++ ) {
        if ( index_out_envelop < out_envelop_length ) {
            out_envelop_bytes[index_out_envelop] = in_envelop_bytes[index];
            index_out_envelop++;
        }

    }

    return final_ret;
}

int xrn_extract_steg_raw_bytes( uint8_t * envelop_bytes, uint64_t envelop_length, uint8_t * out_block_bytes,
                                uint64_t out_block_length, uint64_t * out_block_written_bytes
 )
{

    XPRINT_DEB(  );

    uint32_t tmp32;
    uint64_t index_envelop, index_out_block;
    uint8_t out8;
    int final_ret, j;

    final_ret = XSUCCESS;

    index_envelop = 0;
    index_out_block = 0;

    if ( ( envelop_bytes == NULL ) || ( out_block_bytes == NULL ) || ( out_block_written_bytes == NULL ) ) {
        XPRINT_ERR( 638, XERR_NULL_MSG );
        return XERR_NULL;
    }

    while ( ( index_envelop + 4 < envelop_length ) && ( index_out_block < out_block_length ) ) {

        for ( j = 0; j < 4; j++ ) {
            ( ( uint8_t * ) & tmp32 )[j] = envelop_bytes[index_envelop];
            index_envelop++;
        }

        out8 = steg_decode( tmp32 );

        if ( out_block_length < index_out_block + 1 ) {
            XPRINT_ERR( 640, XERR_IO_MSG );
            return XERR_IO;
        }

        out_block_bytes[index_out_block] = out8;
        index_out_block++;

    }

    *out_block_written_bytes = index_out_block;

    return final_ret;

}

int xrn_make_steg_block_bytes( uint8_t * encoded_bytes, uint64_t encoded_bytes_length,
                               uint8_t * in_envelop_bytes, uint64_t in_envelop_length,
                               uint8_t * out_envelop_bytes, uint64_t out_envelop_length, uint8_t folding_en,
                               uint32_t tag, uint64_t offset, uint64_t length,
                               xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint8_t c;
    uint32_t crc;
    uint64_t capacity, index;
    uint8_t crc8;
    uint8_t encoding_guard_tmp[256];
    uint32_t tmp32, out32;
    xrn_encoding_param_t enc_param;
    xrn_encoding_tmp_param_t enc_tmp;
    int i, j, fold;
    uint64_t index_in_envelop, index_out_envelop, index_encoded;
    int ret, final_ret;

    header_block_t header;

    final_ret = XSUCCESS;

    index_in_envelop = 0;
    index_out_envelop = 0;
    index_encoded = offset;

    if ( ( encoded_bytes == NULL ) || ( in_envelop_bytes == NULL ) || ( out_envelop_bytes == NULL ) ) {
        XPRINT_ERR( 1149, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( ( folding_en != 0 ) && ( folding_en != 1 ) ) {
        XPRINT_ERR( 1174, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1148, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // initialize encoding decoding param
    ret = xrn_initialize_encoding_parameters( &enc_param, settings.encoding_settings.o_settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1147, XERR_GENERAL_MSG );
        return ret;
    }

    crc = 0xffffffff;

    for ( i = 0; i < sizeof( header ); i++ ) {
        ( ( uint8_t * ) & header )[i] = 0;
    }

    header.total_length = encoded_bytes_length;

    // validate the offset and length
    if ( ( length < 0 ) || ( offset < 0 ) || ( offset + length > header.total_length ) ) {
        XPRINT_ERR( 1146, XERR_IO_MSG );
        return XERR_IO;
    }

    // get envelop capacity
    if ( XSUCCESS != xrn_estimate_steg_block_length_bytes( encoded_bytes_length, folding_en, &capacity ) ) {
        XPRINT_ERR( 1145, XERR_IO_MSG );
        return XERR_IO;
    }

    // check if the envelop is big enough for the block

    if ( ( folding_en == 1 ) && ( length < 256 ) ) {
        if ( capacity < length + 256 ) {
            XPRINT_ERR( 788, XERR_IO_MSG );
            return XERR_IO;
        }

    } else {
        if ( capacity < length ) {
            XPRINT_ERR( 1172, XERR_IO_MSG );
            return XERR_IO;
        }

    }

    // create encoding guard from encoded file
    fold = 0;
    if ( ( length > 256 ) && ( folding_en == 1 ) ) {

        if ( encoded_bytes_length < index_encoded + 256 ) {
            XPRINT_ERR( 1101, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( i = 0; i < 256; i++ ) {
            encoding_guard_tmp[i] = encoded_bytes[index_encoded];
            index_encoded++;
        }

        // calculate crc
        xrn_crc32( ( uint8_t * ) & encoding_guard_tmp[0], 256, &crc );
        fold = 1;

        // create encoding guard randomly
    } else {
        if ( XSUCCESS != get_random_bytes( ( uint8_t * ) & encoding_guard_tmp[0], 256 ) ) {
            XPRINT_ERR( 1144, XERR_IO_MSG );
            return XERR_IO;
        }

    }

    // encode encoding_guard
    ret = xrn_encode( &enc_param, encoding_guard_tmp, encoding_guard_tmp, 256, &enc_tmp );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {

        XPRINT_ERR( 1143, XERR_GENERAL_MSG );
        return ret;
    }

    // generate steganography encoding_guard
    for ( i = 0; i < 256; i++ ) {

        if ( in_envelop_length < index_in_envelop + 4 ) {
            XPRINT_ERR( 1102, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            ( ( uint8_t * ) & tmp32 )[j] = in_envelop_bytes[index_in_envelop];
            index_in_envelop++;
        }

        out32 = steg_encode( encoding_guard_tmp[i], tmp32 );

        if ( out_envelop_length < index_out_envelop + 4 ) {
            XPRINT_ERR( 1103, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            out_envelop_bytes[index_out_envelop] = ( ( uint8_t * ) & out32 )[j];
            index_out_envelop++;
        }

    }

    // write the magic number to the output file

    if ( folding_en == 0 ) {
        header.magic_number = XRN_MAGIC_NUMBER_BLOCK;
    } else {
        header.magic_number = XRN_MAGIC_NUMBER_ENCODED_BLOCK;
    }

    header.tag = tag;
    header.offset = offset;
    header.length = length;
    header.crc8 = 0xff;
    crc8 = 0xff;
    xrn_crc8( ( uint8_t * ) & header, sizeof( header ) - 1, &crc8 );
    header.crc8 = crc8;

    // encode header

    ret =
        xrn_encode( &enc_param, ( uint8_t * ) & header, ( uint8_t * ) & header, sizeof( header ), &enc_tmp );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {

        XPRINT_ERR( 1142, XERR_GENERAL_MSG );
        return ret;
    }

    // write header with steganography

    for ( i = 0; i < sizeof( header ); i++ ) {

        if ( in_envelop_length < index_in_envelop + 4 ) {
            XPRINT_ERR( 1104, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            ( ( uint8_t * ) & tmp32 )[j] = in_envelop_bytes[index_in_envelop];
            index_in_envelop++;
        }

        out32 = steg_encode( ( ( uint8_t * ) & header )[i], tmp32 );

        if ( out_envelop_length < index_out_envelop + 4 ) {
            XPRINT_ERR( 1105, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            out_envelop_bytes[index_out_envelop] = ( ( uint8_t * ) & out32 )[j];
            index_out_envelop++;
        }

    }

    if ( fold == 1 ) {
        index_encoded = offset + 256;
    }

    // Read and write the specified length of data from the input file to the output file
    while ( ( encoded_bytes_length > index_encoded ) && ( ( index_encoded - offset ) < length ) ) {

        c = encoded_bytes[index_encoded];
        index_encoded++;

        // calculate crc
        xrn_crc32( &c, 1, &crc );

        // encode buffer

        ret = xrn_encode( &enc_param, &c, &c, 1, &enc_tmp );

        final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
        if ( final_ret == XERR_GENERAL ) {

            XPRINT_ERR( 1141, XERR_GENERAL_MSG );
            return ret;
        }

        // write buffer with steganography

        if ( in_envelop_length < index_in_envelop + 4 ) {
            XPRINT_ERR( 1154, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            ( ( uint8_t * ) & tmp32 )[j] = in_envelop_bytes[index_in_envelop];
            index_in_envelop++;
        }

        out32 = steg_encode( c, tmp32 );

        if ( out_envelop_length < index_out_envelop + 4 ) {
            XPRINT_ERR( 1123, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            out_envelop_bytes[index_out_envelop] = ( ( uint8_t * ) & out32 )[j];
            index_out_envelop++;
        }

    }

    // encode crc

    ret = xrn_encode( &enc_param, ( uint8_t * ) & crc, ( uint8_t * ) & crc, sizeof( crc ), &enc_tmp );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {

        XPRINT_ERR( 1140, XERR_GENERAL_MSG );
        return ret;
    }

    // write buffer with steganography

    for ( i = 0; i < sizeof( uint32_t ); i++ ) {

        if ( in_envelop_length < index_in_envelop + 4 ) {
            XPRINT_ERR( 1124, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            ( ( uint8_t * ) & tmp32 )[j] = in_envelop_bytes[index_in_envelop];
            index_in_envelop++;
        }

        out32 = steg_encode( ( ( uint8_t * ) & crc )[i], tmp32 );

        if ( out_envelop_length < index_out_envelop + 4 ) {
            XPRINT_ERR( 1125, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            out_envelop_bytes[index_out_envelop] = ( ( uint8_t * ) & out32 )[j];
            index_out_envelop++;
        }

    }

    for ( index = index_in_envelop; index < in_envelop_length; index++ ) {
        if ( index_out_envelop < out_envelop_length ) {
            out_envelop_bytes[index_out_envelop] = in_envelop_bytes[index];
            index_out_envelop++;
        }

    }

    return final_ret;
}

int xrn_extract_steg_block_bytes( uint8_t * envelop_bytes, uint64_t envelop_length, uint8_t * out_block_bytes,
                                  uint64_t out_block_length, uint64_t * out_block_written_bytes,
                                  xrn_crypto_extra_settings_t settings
 )
{

    XPRINT_DEB(  );

    uint8_t folding_en, encoding_guard_tmp[256];
    uint32_t tmp32, crc, crc_stored;
    uint64_t total_length;
    uint64_t index_envelop, index_out_block;
    uint8_t out8, crc8, crc8_stored;
    int ret, final_ret, i, j;
    header_block_t header;
    xrn_encoding_param_t enc_param;
    xrn_encoding_tmp_param_t enc_tmp;

    final_ret = XSUCCESS;
    crc = 0xffffffff;

    index_envelop = 0;
    index_out_block = 0;

    if ( ( envelop_bytes == NULL ) || ( out_block_bytes == NULL ) || ( out_block_written_bytes == NULL ) ) {
        XPRINT_ERR( 1164, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1163, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // initialize encoding decoding param
    ret = xrn_initialize_encoding_parameters( &enc_param, settings.encoding_settings.i_settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1162, XERR_GENERAL_MSG );
        return ret;
    }

    // fetch encoding guard
    for ( i = 0; i < 256; i++ ) {

        if ( envelop_length < index_envelop + 4 ) {
            XPRINT_ERR( 1155, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            ( ( uint8_t * ) & tmp32 )[j] = envelop_bytes[index_envelop];
            index_envelop++;
        }

        out8 = steg_decode( tmp32 );

        // encode crc

        ret = xrn_decode( &enc_param, &out8, &out8, 1, &enc_tmp );

        final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
        if ( final_ret == XERR_GENERAL ) {

            XPRINT_ERR( 1161, XERR_GENERAL_MSG );
            return ret;
        }

        encoding_guard_tmp[i] = out8;

    }

    // fetch header
    for ( i = 0; i < sizeof( header ); i++ ) {

        if ( envelop_length < index_envelop + 4 ) {
            XPRINT_ERR( 1156, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            ( ( uint8_t * ) & tmp32 )[j] = envelop_bytes[index_envelop];
            index_envelop++;
        }

        out8 = steg_decode( tmp32 );

        // encode crc

        ret = xrn_decode( &enc_param, &out8, &out8, 1, &enc_tmp );

        final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
        if ( final_ret == XERR_GENERAL ) {

            XPRINT_ERR( 1106, XERR_GENERAL_MSG );
            return ret;
        }

        ( ( uint8_t * ) & header )[i] = out8;

    }

    crc8_stored = header.crc8;
    header.crc8 = 0xff;
    crc8 = 0xff;
    xrn_crc8( ( uint8_t * ) & header, sizeof( header ) - 1, &crc8 );

    if ( crc8_stored != crc8 ) {
        XPRINT_ERR( 1077, XERR_CRC_MSG );
        return XERR_CRC;
    }

    header.crc8 = crc8_stored;

    if ( header.magic_number == XRN_MAGIC_NUMBER_ENCODED_BLOCK ) {
        folding_en = 1;
        header.magic_number = XRN_MAGIC_NUMBER_BLOCK;
        header.crc8 = 0xff;
        crc8 = 0xff;
        xrn_crc8( ( uint8_t * ) & header, sizeof( header ) - 1, &crc8 );
        header.crc8 = crc8;
    } else {
        folding_en = 0;
    }

    for ( i = 0; i < sizeof( header ); i++ ) {
        if ( out_block_length < index_out_block + 1 ) {
            XPRINT_ERR( 1157, XERR_IO_MSG );
            return XERR_IO;
        }

        out_block_bytes[index_out_block] = ( ( uint8_t * ) & header )[i];
        index_out_block++;
    }

    // unfold
    if ( ( header.length > 256 ) && ( folding_en == 1 ) ) {

        xrn_crc32( ( uint8_t * ) & encoding_guard_tmp[0], 256, &crc );

        for ( i = 0; i < 256; i++ ) {
            out_block_bytes[index_out_block] = encoding_guard_tmp[i];
            index_out_block++;
        }

        total_length = header.length - 256 + 4;

    } else {

        total_length = header.length + 4;

    }

    for ( i = 0; i < total_length; i++ ) {

        if ( envelop_length < index_envelop + 4 ) {
            XPRINT_ERR( 1159, XERR_IO_MSG );
            return XERR_IO;
        }

        for ( j = 0; j < 4; j++ ) {
            ( ( uint8_t * ) & tmp32 )[j] = envelop_bytes[index_envelop];
            index_envelop++;
        }

        out8 = steg_decode( tmp32 );

        // encode crc

        ret = xrn_decode( &enc_param, &out8, &out8, 1, &enc_tmp );

        final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
        if ( final_ret == XERR_GENERAL ) {

            XPRINT_ERR( 1153, XERR_GENERAL_MSG );
            return ret;
        }

        if ( out_block_length < index_out_block + 1 ) {
            XPRINT_ERR( 1160, XERR_IO_MSG );
            return XERR_IO;
        }

        out_block_bytes[index_out_block] = out8;
        index_out_block++;

        if ( i < total_length - 4 ) {
            xrn_crc32( &out8, 1, &crc );
        } else {
            ( ( uint8_t * ) & crc_stored )[3 - ( total_length - ( uint64_t ) i - ( uint64_t ) 1 )] = out8;
        }

        if ( i == total_length - 1 ) {
            if ( crc_stored != crc ) {
                XPRINT_ERR( 1165, XERR_CRC_MSG );
                return XERR_CRC;
            }

        }

    }

    *out_block_written_bytes = index_out_block;

    return final_ret;

}

int xrn_decode_encode_bytes_wrapper( uint8_t * in_bytes, uint8_t * out_bytes, uint64_t length,
                                     xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );
    int ret, final_ret;
    xrn_encoding_interface_t enc_interface;

    if ( ( in_bytes == NULL ) || ( out_bytes == NULL ) ) {
        XPRINT_ERR( 276, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 277, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // initialize encoding interface

    ret = xrn_initialize_encoding_interface( &enc_interface, settings.encoding_settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 278, XERR_GENERAL_MSG );
        return ret;
    }

    // read the entire file

    ret = xrn_decode_encode_bytes( in_bytes, out_bytes, 0, length, &enc_interface );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 279, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_make_commitment_from_sym_signatures_bytes_wrapper( uint8_t * in_bytes,
                                                           uint64_t in_length,
                                                           FILE * xrn_matrix_fpr,
                                                           FILE * signature_fpr,
                                                           FILE * monomial_commitment_fpw,
                                                           FILE * binomial_commitment_fpw,
                                                           xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int i, ret, final_ret;
    xrn_matrix_t *xrn_matrix;
    xsignature_sym_t signature_sym;
    xmonomial_commitment_t monomial_commitment;
    xbinomial_commitment_t binomial_commitment;

    if ( ( in_bytes == NULL ) || ( xrn_matrix_fpr == NULL ) || ( signature_fpr == NULL )
         || ( monomial_commitment_fpw == NULL )
         || ( binomial_commitment_fpw == NULL ) ) {
        XPRINT_ERR( 432, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 433, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    for ( i = 0; i < sizeof( monomial_commitment ); i++ ) {
        ( ( uint8_t * ) & monomial_commitment )[i] = 0;
    }

    for ( i = 0; i < sizeof( binomial_commitment ); i++ ) {
        ( ( uint8_t * ) & binomial_commitment )[i] = 0;
    }

    for ( i = 0; i < sizeof( signature_sym ); i++ ) {
        ( ( uint8_t * ) & signature_sym )[i] = 0;
    }

    // load matrix        

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 434, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 435, XERR_GENERAL_MSG );
        return ret;
    }

    // compute commitment

    ret = xrn_load_signature_sym( &signature_sym, signature_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 436, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_make_commitment_from_sym_signature_bytes( in_bytes, in_length, xrn_matrix, signature_sym,
                                                      &monomial_commitment, &binomial_commitment, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 437, XERR_GENERAL_MSG );
        return ret;
    }

    // dump results

    XRN_FREE( xrn_matrix );

    ret = xrn_dump_monomial_commitment( monomial_commitment, monomial_commitment_fpw, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 438, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_dump_binomial_commitment( binomial_commitment, binomial_commitment_fpw, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 439, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_make_commitment_from_sym_signature_bytes( uint8_t * in_bytes,
                                                  uint64_t in_length,
                                                  xrn_matrix_t * xrn_matrix,
                                                  xsignature_sym_t signature,
                                                  xmonomial_commitment_t * monomial_commitment,
                                                  xbinomial_commitment_t * binomial_commitment,
                                                  xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int ret, final_ret, i;
    xhash_t hash;
    xbinomial_key_t binomial_key;
    xrn_log_t xlog2;

    if ( ( in_bytes == NULL ) || ( xrn_matrix == NULL ) || ( monomial_commitment == NULL )
         || ( binomial_commitment == NULL ) ) {
        XPRINT_ERR( 440, XERR_NULL_MSG );
        return XERR_NULL;
    }

    for ( i = 0; i < sizeof( binomial_key ); i++ ) {
        ( ( uint8_t * ) & binomial_key )[i] = 0;
    }

    for ( i = 0; i < sizeof( hash ); i++ ) {
        ( ( uint8_t * ) & hash )[i] = 0;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 441, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // check if xoron matrix is correct
    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 442, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );

        final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
        if ( final_ret == XERR_GENERAL ) {
            XPRINT_ERR( 443, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // compute hash
    ret = xrn_make_hash_bytes( in_bytes, in_length, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 444, XERR_GENERAL_MSG );
        return ret;
    }

    binomial_key.start = hash.value;
    binomial_key.end = signature.proof;

    ret =
        xrn_make_commitment_from_binomial_key( binomial_key, xrn_matrix, monomial_commitment,
                                               binomial_commitment, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 445, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_make_monomial_proof_from_signature_bytes_wrapper( uint8_t * in_bytes, uint64_t in_length,
                                                          FILE * xrn_matrix_fpr, FILE * signature_fpr,
                                                          FILE * monomial_key_fpr,
                                                          FILE * monomial_commitment_fpr,
                                                          FILE * monomial_response_fpr,
                                                          FILE * monomial_proof_fpw,
                                                          xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int i, ret, final_ret;
    xrn_matrix_t *xrn_matrix;
    xmonomial_key_t monomial_key;
    xsignature_sym_t signature;
    xmonomial_commitment_t monomial_commitment;
    xmonomial_response_t monomial_response;
    xmonomial_proof_t monomial_proof;

    if ( ( in_bytes == NULL ) || ( signature_fpr == NULL ) || ( xrn_matrix_fpr == NULL )
         || ( monomial_key_fpr == NULL )
         || ( monomial_commitment_fpr == NULL ) || ( monomial_response_fpr == NULL )
         || ( monomial_proof_fpw == NULL ) ) {
        XPRINT_ERR( 467, XERR_NULL_MSG );
        return XERR_NULL;
    }

    for ( i = 0; i < sizeof( monomial_key ); i++ ) {
        ( ( uint8_t * ) & monomial_key )[i] = 0;
    }

    for ( i = 0; i < sizeof( signature ); i++ ) {
        ( ( uint8_t * ) & signature )[i] = 0;
    }

    for ( i = 0; i < sizeof( monomial_commitment ); i++ ) {
        ( ( uint8_t * ) & monomial_commitment )[i] = 0;
    }

    for ( i = 0; i < sizeof( monomial_response ); i++ ) {
        ( ( uint8_t * ) & monomial_response )[i] = 0;
    }

    for ( i = 0; i < sizeof( monomial_proof ); i++ ) {
        ( ( uint8_t * ) & monomial_proof )[i] = 0;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 468, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // load signature

    ret = xrn_load_signature_sym( &signature, signature_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 469, XERR_GENERAL_MSG );
        return ret;
    }

    // load monomial key

    ret = xrn_load_monomial_key( &monomial_key, monomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 470, XERR_GENERAL_MSG );
        return ret;
    }

    // load monomial commitment

    ret = xrn_load_monomial_commitment( &monomial_commitment, monomial_commitment_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 471, XERR_GENERAL_MSG );
        return ret;
    }

    // load monomial response

    ret = xrn_load_monomial_response( &monomial_response, monomial_response_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 472, XERR_GENERAL_MSG );
        return ret;
    }

    // load matrix        

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 473, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 474, XERR_GENERAL_MSG );
        return ret;
    }

    // compute monomial proof

    ret =
        xrn_make_monomial_proof_from_signature_bytes( in_bytes, in_length, xrn_matrix, signature,
                                                      monomial_key, monomial_commitment,
                                                      monomial_response, &monomial_proof, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 475, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE( xrn_matrix );

    // dump monomial proof

    ret = xrn_dump_monomial_proof( monomial_proof, monomial_proof_fpw, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 476, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_make_monomial_proof_from_signature_bytes( uint8_t * in_bytes, uint64_t in_length,
                                                  xrn_matrix_t * xrn_matrix, xsignature_sym_t signature,
                                                  xmonomial_key_t monomial_key,
                                                  xmonomial_commitment_t monomial_commitment,
                                                  xmonomial_response_t monomial_response,
                                                  xmonomial_proof_t * monomial_proof,
                                                  xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int carry, greater, ret, final_ret, i;
    xbinomial_commitment_t binomial_commitment;
    xnum_t distance_commitment_response, zero, proof_distance;
    xhash_t hash;
    xbinomial_key_t binomial_key;
    uint8_t constant_execution, force_linearity, check_sparcity;
    xrn_log_t xlog2;

    if ( ( in_bytes == NULL ) || ( xrn_matrix == NULL ) || ( monomial_proof == NULL ) ) {
        XPRINT_ERR( 477, XERR_NULL_MSG );
        return XERR_NULL;
    }

    constant_execution = settings.const_exec_time;
    final_ret = XSUCCESS;
    force_linearity = 1;
    check_sparcity = 1;

    for ( i = 0; i < sizeof( binomial_commitment ); i++ ) {
        ( ( uint8_t * ) & binomial_commitment )[i] = 0;
    }

    for ( i = 0; i < sizeof( hash ); i++ ) {
        ( ( uint8_t * ) & hash )[i] = 0;
    }

    for ( i = 0; i < sizeof( binomial_key ); i++ ) {
        ( ( uint8_t * ) & binomial_key )[i] = 0;
    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 478, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;
    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 479, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );

        final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
        if ( final_ret == XERR_GENERAL ) {
            XPRINT_ERR( 480, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // compute hash
    ret = xrn_make_hash_bytes( in_bytes, in_length, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 481, XERR_GENERAL_MSG );
        return ret;
    }

    binomial_key.start = hash.value;
    binomial_key.end = signature.proof;

    // calculate binomial commitment

    binomial_commitment.start = binomial_key.start;

    ret =
        xrn_matrix_traverse( xrn_matrix, &binomial_commitment.start,
                             &monomial_commitment.distance, &binomial_commitment.end, &constant_execution,
                             &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 482, XERR_GENERAL_MSG );
        return ret;
    }

    // modify monomial key

    ret =
        xrn_matrix_traverse( xrn_matrix, &signature.hint, &monomial_key.distance,
                             &monomial_key.distance, &constant_execution, &force_linearity, &check_sparcity );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 483, XERR_GENERAL_MSG );
        return ret;
    }

    // calculate distance between monomial_response and monomial_commitment

    xrn_initialize_num( &zero );

    carry =
        xrn_add_nums( monomial_commitment.distance, monomial_response.distance, 0,
                      &distance_commitment_response );
    while ( carry == 1 ) {

        carry = xrn_add_nums( distance_commitment_response, zero, 1, &distance_commitment_response );

    }

    xrn_compare_greater_equal_nums( distance_commitment_response, monomial_key.distance, &greater );

    // invert distance

    if ( greater == 1 ) {

        // calculate distance between the previous sum and monomial key
        xrn_subtract_nums( distance_commitment_response, monomial_key.distance, &proof_distance );

    } else {

        // calculate distance between the previous sum and monomial key
        xrn_subtract_nums( monomial_key.distance, distance_commitment_response, &proof_distance );

    }

    monomial_proof->distance = proof_distance;

    return final_ret;

}

int xrn_check_monomial_proof_from_signature_bytes_wrapper( uint8_t * in_bytes,
                                                           uint64_t in_length,
                                                           FILE * xrn_matrix_fpr,
                                                           FILE * signature_fpr,
                                                           FILE * binomial_commitment_fpr,
                                                           FILE * monomial_response_fpr,
                                                           FILE * monomial_proof_fpr,
                                                           xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int final_ret, ret;
    xrn_matrix_t *xrn_matrix;
    xsignature_sym_t signature_sym;
    xmonomial_response_t monomial_response;
    xmonomial_proof_t monomial_proof;
    xbinomial_commitment_t binomial_commitment;

    if ( ( in_bytes == NULL ) || ( xrn_matrix_fpr == NULL ) || ( signature_fpr == NULL )
         || ( monomial_proof_fpr == NULL ) || ( monomial_response_fpr == NULL )
         || ( binomial_commitment_fpr == NULL ) ) {
        XPRINT_ERR( 549, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 550, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // load binomial commitment

    ret = xrn_load_binomial_commitment( &binomial_commitment, binomial_commitment_fpr, &settings );
    if ( XSUCCESS != ret ) {
        XPRINT_ERR( 551, XERR_GENERAL_MSG );
        return ret;
    }

    // load monomial response

    ret = xrn_load_monomial_response( &monomial_response, monomial_response_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 552, XERR_GENERAL_MSG );
        return ret;
    }

    // load monomial response

    ret = xrn_load_monomial_proof( &monomial_proof, monomial_proof_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 553, XERR_GENERAL_MSG );
        return ret;
    }

    // load matrix        

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 554, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 555, XERR_GENERAL_MSG );
        return ret;
    }

    // compute commitment

    ret = xrn_load_signature_sym( &signature_sym, signature_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 556, XERR_GENERAL_MSG );
        return ret;
    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 557, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    ret =
        xrn_check_monomial_proof_from_signature_bytes( in_bytes, in_length, xrn_matrix, signature_sym,
                                                       binomial_commitment, monomial_response, monomial_proof,
                                                       settings );

    XRN_FREE( xrn_matrix );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 558, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_check_monomial_proof_from_signature_bytes( uint8_t * in_bytes,
                                                   uint64_t in_length,
                                                   xrn_matrix_t * xrn_matrix,
                                                   xsignature_sym_t signature,
                                                   xbinomial_commitment_t binomial_commitment,
                                                   xmonomial_response_t monomial_response,
                                                   xmonomial_proof_t monomial_proof,
                                                   xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int final_ret, ret;
    xhash_t hash;
    xbinomial_key_t binomial_key;
    xrn_log_t xlog2;

    if ( ( in_bytes == NULL ) || ( xrn_matrix == NULL ) ) {
        XPRINT_ERR( 559, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 560, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 561, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );

        final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
        if ( final_ret == XERR_GENERAL ) {
            XPRINT_ERR( 562, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // compute hash
    ret = xrn_make_hash_bytes( in_bytes, in_length, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 563, XERR_GENERAL_MSG );
        return ret;
    }

    binomial_key.start = hash.value;
    binomial_key.end = signature.proof;

    ret =
        xrn_check_monomial_proof( binomial_key, xrn_matrix, binomial_commitment, monomial_response,
                                  monomial_proof, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 564, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_split_bytes_wrapper( uint8_t * in_bytes,
                             uint64_t in_length,
                             uint8_t * out_bytes_challenge,
                             uint64_t out_length_challenge,
                             uint64_t * num_encoded_bytes_challenge,
                             uint8_t * out_bytes_solution,
                             uint64_t out_length_solution,
                             uint64_t * num_encoded_bytes_solution, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int final_ret, ret;

    if ( ( in_bytes == NULL ) || ( out_bytes_challenge == NULL ) || ( num_encoded_bytes_challenge == NULL )
         || ( out_bytes_solution == NULL ) || ( num_encoded_bytes_solution == NULL )
         ) {
        XPRINT_ERR( 674, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 675, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    ret =
        xrn_split_bytes( in_bytes, in_length, out_bytes_challenge, out_length_challenge,
                         num_encoded_bytes_challenge, out_bytes_solution, out_length_solution,
                         num_encoded_bytes_solution, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 678, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;
}

int xrn_split_bytes( uint8_t * in_bytes,
                     uint64_t in_length,
                     uint8_t * out_bytes_challenge,
                     uint64_t out_length_challenge,
                     uint64_t * num_encoded_bytes_challenge,
                     uint8_t * out_bytes_solution,
                     uint64_t out_length_solution,
                     uint64_t * num_encoded_bytes_solution, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_lib_xtype_t type;
    uint64_t id;
    int i;
    uint64_t estimated_out_buff0, estimated_out_buff1;
    int final_ret, ret;
    xrn_encoding_tmp_param_t enc_param_tmp;
    xrn_encoding_param_t enc_param_challenge, enc_param_solution;
    xrn_crypto_lib_header_t header_solution, header_challenge_encguard;

    if ( ( in_bytes == NULL ) || ( out_bytes_challenge == NULL ) || ( num_encoded_bytes_challenge == NULL )
         || ( num_encoded_bytes_solution == NULL ) || ( out_bytes_challenge == NULL )
         || ( out_bytes_solution == NULL ) ) {
        XPRINT_ERR( 679, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 684, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    if ( settings.state_size <= 2 ) {
        XPRINT_ERR( 685, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // initialize encoding decoding param
    ret = xrn_initialize_encoding_parameters( &enc_param_solution, settings.encoding_settings.o_settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 149, XERR_GENERAL_MSG );
        return ret;
    }

    // dump solution header

    type = c_solution;
    ret = xrn_initialize_header( type,
                                 settings.crc_bytes,
                                 settings.state_size, settings.component_id, &header_solution );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 646, XERR_GENERAL_MSG );
        return ret;
    }

    // using encoding_guard as password for enc_param_challenge

    ret = xrn_permute_encoding_param_with_pass( enc_param_solution, header_solution.encoding_guard,
                                                sizeof( header_solution.encoding_guard ),
                                                &enc_param_challenge );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 59, XERR_GENERAL_MSG );
        return ret;
    }

    // encoding header solution

    if ( out_length_solution < xrn_estimate_solution_block_bytes_length(  ) ) {
        XPRINT_ERR( 150, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( XSUCCESS !=
         xrn_encode( &enc_param_solution, ( uint8_t * ) & header_solution, out_bytes_solution,
                     sizeof( header_solution ), &enc_param_tmp ) ) {
        XPRINT_ERR( 148, XERR_IO_MSG );
        return XERR_IO;
    }

    *num_encoded_bytes_solution = ( uint64_t ) sizeof( header_solution );

    // dump challenge header

    type = c_challenge;
    ret = xrn_initialize_header( type,
                                 settings.crc_bytes,
                                 settings.state_size, settings.component_id, &header_challenge_encguard );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 0, XERR_GENERAL_MSG );
        return ret;
    }

    if ( out_length_challenge < sizeof( header_challenge_encguard ) ) {
        XPRINT_ERR( 151, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( XSUCCESS !=
         xrn_encode( &enc_param_challenge, ( uint8_t * ) & header_challenge_encguard, out_bytes_challenge,
                     sizeof( header_challenge_encguard ), &enc_param_tmp ) ) {
        XPRINT_ERR( 152, XERR_IO_MSG );
        return XERR_IO;
    }

    *num_encoded_bytes_challenge = ( uint64_t ) sizeof( header_challenge_encguard );

    estimated_out_buff0 = 0;
    estimated_out_buff1 = 0;

    ret =
        xrn_estimate_split_bytes_length( type, in_length, &estimated_out_buff0, &estimated_out_buff1,
                                         settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 689, XERR_GENERAL_MSG );
        return ret;
    }

    if ( ( out_length_challenge < estimated_out_buff0 ) || ( out_length_solution < estimated_out_buff1 ) ) {
        XPRINT_ERR( 690, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    // encoding bytes

    if ( XSUCCESS != get_random_bytes( ( uint8_t * ) & id, sizeof( uint64_t ) ) ) {
        XPRINT_ERR( 695, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( ( *num_encoded_bytes_challenge ) + sizeof( uint64_t ) > out_length_challenge ) {
        XPRINT_ERR( 696, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    if ( ( *num_encoded_bytes_solution ) + sizeof( uint64_t ) > out_length_solution ) {
        XPRINT_ERR( 697, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    for ( i = 0; i < sizeof( uint64_t ); i++ ) {

        out_bytes_challenge[( *num_encoded_bytes_challenge )] = ( ( uint8_t * ) ( &id ) )[i];
        out_bytes_solution[( *num_encoded_bytes_solution )] = ( ( uint8_t * ) ( &id ) )[i];

        ( *num_encoded_bytes_challenge )++;
        ( *num_encoded_bytes_solution )++;
    }

    // encoding bytes

    ret =
        xrn_encode( &enc_param_challenge,
                    &out_bytes_challenge[( *num_encoded_bytes_challenge ) - sizeof( uint64_t )],
                    &out_bytes_challenge[( *num_encoded_bytes_challenge ) - sizeof( uint64_t )],
                    sizeof( uint64_t ), &enc_param_tmp );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 698, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_encode( &enc_param_solution,
                    &out_bytes_solution[( *num_encoded_bytes_solution ) - sizeof( uint64_t )],
                    &out_bytes_solution[( *num_encoded_bytes_solution ) - sizeof( uint64_t )],
                    sizeof( uint64_t ), &enc_param_tmp );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 699, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        loop_split_bytes( in_bytes, in_length, out_bytes_challenge, out_length_challenge,
                          num_encoded_bytes_challenge, out_bytes_solution, out_length_solution,
                          num_encoded_bytes_solution, enc_param_challenge, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 700, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_join_bytes_wrapper( uint8_t * in_bytes_challenge,
                            uint64_t in_length_challenge,
                            uint8_t * in_bytes_solution,
                            uint64_t in_length_solution,
                            uint8_t * out_bytes,
                            uint64_t out_length,
                            uint64_t * num_decoded_bytes, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int final_ret, ret;

    if ( ( in_bytes_challenge == NULL ) || ( in_bytes_solution == NULL )
         || ( out_bytes == NULL ) || ( num_decoded_bytes == NULL ) ) {
        XPRINT_ERR( 701, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 702, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    ret =
        xrn_join_bytes( in_bytes_challenge, in_length_challenge, in_bytes_solution, in_length_solution,
                        out_bytes, out_length, num_decoded_bytes, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 705, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_join_bytes( uint8_t * in_bytes_challenge,
                    uint64_t in_length_challenge,
                    uint8_t * in_bytes_solution,
                    uint64_t in_length_solution,
                    uint8_t * out_bytes,
                    uint64_t out_length, uint64_t * num_decoded_bytes, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint64_t id0, id1;
    uint64_t i, index_challenge, index_solution, estimated_out_buff_size;
    int ret, final_ret;
    xrn_encoding_tmp_param_t enc_param_tmp;
    xrn_encoding_param_t enc_param_challenge_tmp, enc_param_challenge, enc_param_solution;
    xrn_lib_xtype_t exp_type;
    uint8_t crc_bytes_challenge;
    uint8_t state_size_challenge;
    xrn_lib_xtype_t type_solution;
    uint8_t crc_bytes_solution;
    uint8_t state_size_solution;
    uint32_t reserved_0, reserved_1;
    xrn_lib_xtype_t type_challenge;
    uint32_t reserved_0_challenge, reserved_1_challenge;
    uint8_t encoding_guard_tmp[256];
    xrn_crypto_lib_header_t header_local;

    if ( ( in_bytes_challenge == NULL ) || ( in_bytes_solution == NULL )
         || ( out_bytes == NULL ) || ( num_decoded_bytes == NULL ) ) {
        XPRINT_ERR( 706, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 707, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // load solution header

    if ( in_length_solution < xrn_estimate_solution_block_bytes_length(  ) ) {
        XPRINT_ERR( 1194, XERR_IO_MSG );
        return XERR_IO;
    }

    exp_type = c_solution;
    ret =
        xrn_load_header_bytes( in_bytes_solution, in_length_solution, &crc_bytes_solution,
                               &type_solution, exp_type,
                               &state_size_solution, &index_solution,
                               &reserved_0, &reserved_1, &enc_param_solution, settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 243, XERR_GENERAL_MSG );
        return ret;
    }

    // load challenge header

    // initialize encoding decoding param
    ret = xrn_initialize_encoding_parameters( &enc_param_challenge, settings.encoding_settings.i_settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 249, XERR_GENERAL_MSG );
        return ret;
    }

    enc_param_challenge_tmp = enc_param_challenge;

    ret =
        xrn_decode( &enc_param_challenge_tmp, in_bytes_solution, encoding_guard_tmp,
                    sizeof( encoding_guard_tmp ), &enc_param_tmp );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 241, XERR_VERSION_MSG );
        return XERR_VERSION;
    }

    ret = xrn_permute_encoding_param_with_pass( enc_param_challenge, encoding_guard_tmp,
                                                sizeof( encoding_guard_tmp ), &enc_param_challenge );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 657, XERR_GENERAL_MSG );
        return ret;
    }

    if ( in_length_challenge < ( uint64_t ) sizeof( header_local ) ) {
        XPRINT_ERR( 600, XERR_IO_MSG );
        return XERR_IO;
    }

    ret =
        xrn_decode( &enc_param_challenge, in_bytes_challenge, ( uint8_t * ) & header_local,
                    ( uint64_t ) sizeof( header_local ), &enc_param_tmp );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 247, XERR_VERSION_MSG );
        return XERR_VERSION;
    }

    index_challenge = ( uint64_t ) sizeof( header_local );

    exp_type = c_challenge;
    ret =
        xrn_load_header( header_local, &crc_bytes_challenge,
                         &type_challenge, exp_type,
                         &state_size_challenge, &reserved_0_challenge, &reserved_1_challenge );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2, XERR_GENERAL_MSG );
        return ret;
    }

    if ( ( crc_bytes_challenge != crc_bytes_solution ) || ( state_size_challenge != state_size_solution )
         || ( reserved_0_challenge != reserved_0 ) || ( reserved_1_challenge != reserved_1 ) ) {
        XPRINT_ERR( 645, XERR_IO_MSG );
        return XERR_IO;
    }

    settings.crc_bytes = crc_bytes_challenge;
    settings.state_size = state_size_challenge;

    estimated_out_buff_size = 0;

    ret = xrn_estimate_join_bytes_length( in_length_challenge, &estimated_out_buff_size, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 721, XERR_GENERAL_MSG );
        return ret;
    }

    if ( estimated_out_buff_size > out_length ) {
        XPRINT_ERR( 722, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 723, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    if ( index_challenge + sizeof( uint64_t ) > in_length_challenge ) {
        XPRINT_ERR( 724, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    if ( index_solution + sizeof( uint64_t ) > in_length_solution ) {
        XPRINT_ERR( 725, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    id0 = 0;
    id1 = 0;
    for ( i = 0; i < sizeof( uint64_t ); i++ ) {
        ( ( uint8_t * ) ( &id0 ) )[i] = in_bytes_challenge[index_challenge];
        ( ( uint8_t * ) ( &id1 ) )[i] = in_bytes_solution[index_solution];
        index_challenge++;
        index_solution++;
    }

    ret =
        xrn_decode( &enc_param_challenge, ( uint8_t * ) & id0, ( uint8_t * ) & id0, sizeof( uint64_t ),
                    &enc_param_tmp );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 726, XERR_VERSION_MSG );
        return XERR_VERSION;
    }

    ret =
        xrn_decode( &enc_param_solution, ( uint8_t * ) & id1, ( uint8_t * ) & id1, sizeof( uint64_t ),
                    &enc_param_tmp );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 727, XERR_VERSION_MSG );
        return XERR_VERSION;
    }

    if ( id0 != id1 ) {
        XPRINT_ERR( 728, XERR_JOIN_MSG );
        return XERR_JOIN;
    }

    if ( settings.state_size <= 2 ) {
        XPRINT_ERR( 729, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    ret =
        loop_join_bytes( in_bytes_challenge, in_length_challenge,
                         index_challenge, in_bytes_solution, in_length_solution,
                         index_solution, out_bytes, out_length,
                         num_decoded_bytes, enc_param_challenge, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 730, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_check_signature_asymmetric_bytes_wrapper( uint8_t * in_buff_bytes,
                                                  uint64_t in_buff_length,
                                                  FILE * binomial_key_fpr,
                                                  FILE * xrn_matrix_fpr,
                                                  FILE * signature_fpr, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t *xrn_matrix;
    xbinomial_key_t mkey;
    xsignature_asy_t sig;
    int final_ret, ret;

    if ( ( in_buff_bytes == NULL ) || ( binomial_key_fpr == NULL ) || ( xrn_matrix_fpr == NULL )
         || ( signature_fpr == NULL ) ) {
        XPRINT_ERR( 854, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 855, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // read signature
    ret = xrn_load_signature_asy( &sig, signature_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 856, XERR_GENERAL_MSG );
        return ret;
    }

    // initialize variables

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 857, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // load binomial key

    ret = xrn_load_binomial_key( &mkey, binomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 858, XERR_GENERAL_MSG );
        return ret;
    }

    // load xoron matrix
    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 859, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_check_signature_asymmetric_bytes( in_buff_bytes, in_buff_length, mkey, xrn_matrix, sig,
                                              settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 860, XERR_GENERAL_MSG );
        return ret;

    }

    // free memory

    XRN_FREE( xrn_matrix );

    return final_ret;

}

int xrn_check_signature_asymmetric_bytes( uint8_t * in_buff_bytes,
                                          uint64_t in_buff_length,
                                          xbinomial_key_t binomial_key,
                                          xrn_matrix_t * xrn_matrix,
                                          xsignature_asy_t signature, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int error0, error1;
    xnum_t tmp, sig_ver0, sig_ver1;
    xhash_t hash;
    int ret;
    int final_ret;
    uint8_t constant_execution, force_linearity, check_sparcity;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL ) || ( xrn_matrix == NULL ) ) {
        XPRINT_ERR( 861, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;
    constant_execution = settings.const_exec_time;
    force_linearity = 1;
    check_sparcity = 1;

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 862, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 863, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 864, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    ret = xrn_make_hash_bytes( in_buff_bytes, in_buff_length, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 865, XERR_GENERAL_MSG );
        return ret;
    }

    // verify signature

    ret =
        xrn_matrix_traverse( xrn_matrix, &signature.hint, &hash.value, &tmp, &constant_execution,
                             &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 866, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_matrix_traverse( xrn_matrix, &tmp, &signature.proof, &sig_ver0, &constant_execution,
                             &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 867, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_matrix_traverse( xrn_matrix, &binomial_key.end, &signature.proof, &sig_ver1,
                             &constant_execution, &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 868, XERR_GENERAL_MSG );
        return ret;
    }

    XNUM_CMP( sig_ver0, binomial_key.end, error0 );
    XNUM_CMP( sig_ver1, tmp, error1 );

    if ( ( error1 != 0 ) && ( error0 != 0 ) ) {
        XPRINT_NOT( 1 );
        ret = ( int ) XWAR_SIG;
    } else {
        XPRINT_NOT( 0 );
    }

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );

    return final_ret;

}

int xrn_make_signature_asymmetric_bytes_wrapper( uint8_t * in_buff_bytes,
                                                 uint64_t in_buff_length,
                                                 FILE * monomial_key_fpr,
                                                 FILE * binomial_key_fpr,
                                                 FILE * xrn_matrix_fpr,
                                                 FILE * signature_fpw, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t *xrn_matrix;
    xmonomial_key_t mk;
    xbinomial_key_t bk;
    xsignature_asy_t sig;
    int final_ret, ret;

    if ( ( in_buff_bytes == NULL ) || ( monomial_key_fpr == NULL ) || ( binomial_key_fpr == NULL )
         || ( xrn_matrix_fpr == NULL )
         || ( signature_fpw == NULL ) ) {
        XPRINT_ERR( 884, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 885, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // initialize variables

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 886, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // load xoron matrix

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 887, XERR_GENERAL_MSG );
        return ret;
    }

    // load monomial key
    ret = xrn_load_monomial_key( &mk, monomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 888, XERR_GENERAL_MSG );
        return ret;
    }

    // load binomial key
    ret = xrn_load_binomial_key( &bk, binomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 889, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_make_signature_asymmetric_bytes( in_buff_bytes, in_buff_length, mk, bk, xrn_matrix, &sig,
                                             settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 890, XERR_GENERAL_MSG );
        return ret;
    }

    // write signature
    ret = xrn_dump_signature_asy( sig, signature_fpw, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 891, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE( xrn_matrix );

    return final_ret;

}

int xrn_make_signature_asymmetric_bytes( uint8_t * in_buff_bytes,
                                         uint64_t in_buff_length,
                                         xmonomial_key_t monomial_key,
                                         xbinomial_key_t binomial_key,
                                         xrn_matrix_t * xrn_matrix,
                                         xsignature_asy_t * signature, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xnum_t sum, xnum_rnd, hint, zero, proof;
    xhash_t hash;
    int greater, ret, carry, final_ret;
    uint8_t constant_execution, force_linearity, check_sparcity;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL ) || ( xrn_matrix == NULL ) || ( signature == NULL ) ) {
        XPRINT_ERR( 892, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;
    constant_execution = settings.const_exec_time;
    force_linearity = 1;
    check_sparcity = 1;

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 893, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 894, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 895, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // check monomial key sparsity

    ret = xrn_check_sparsity( monomial_key.distance );
    if ( ret == XERR_SPARSE_MKEY ) {
        XPRINT_ERR( 896, XERR_SPARSE_MKEY_MSG );
        return ret;
    }

    // compute hash
    ret = xrn_make_hash_bytes( in_buff_bytes, in_buff_length, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 897, XERR_GENERAL_MSG );
        return ret;
    }

    // compute hint

    ret = xrn_initialize_true_rnd_num( settings.rnd_str, &xnum_rnd );
    if ( XSUCCESS != ret ) {
        XPRINT_ERR( 898, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_matrix_traverse( xrn_matrix, &binomial_key.start, &xnum_rnd, &hint, &constant_execution,
                             &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 899, XERR_GENERAL_MSG );
        return ret;
    }

    // calculate distance between monomial_response and monomial_commitment

    xrn_initialize_num( &zero );
    carry = xrn_add_nums( xnum_rnd, hash.value, 0, &sum );

    while ( carry == 1 ) {

        carry = xrn_add_nums( sum, zero, 1, &sum );

    }

    xrn_compare_greater_equal_nums( sum, monomial_key.distance, &greater );

    // invert distance

    if ( greater == 1 ) {

        // calculate distance between the previous sum and monomial key
        xrn_subtract_nums( sum, monomial_key.distance, &proof );

    } else {

        // calculate distance between the previous sum and monomial key
        xrn_subtract_nums( monomial_key.distance, sum, &proof );

    }

    signature->hint = hint;
    signature->proof = proof;

    return final_ret;

}

int xrn_make_signature_symmetric_bytes_wrapper( uint8_t * in_buff_bytes,
                                                uint64_t in_buff_length,
                                                FILE * monomial_key_fpr,
                                                FILE * xrn_matrix_fpr,
                                                FILE * signature_fpw, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t *xrn_matrix;
    xmonomial_key_t mkey;
    xsignature_sym_t sig;
    int final_ret, ret;

    if ( ( in_buff_bytes == NULL ) || ( monomial_key_fpr == NULL ) || ( xrn_matrix_fpr == NULL )
         || ( signature_fpw == NULL ) ) {
        XPRINT_ERR( 915, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 916, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // initialize variables

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 917, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // load xoron matrix

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 918, XERR_GENERAL_MSG );
        return ret;
    }

    // load monomial key

    ret = xrn_load_monomial_key( &mkey, monomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 919, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_make_signature_symmetric_bytes( in_buff_bytes, in_buff_length, mkey, xrn_matrix, &sig, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 920, XERR_GENERAL_MSG );
        return ret;
    }

    // write signature

    ret = xrn_dump_signature_sym( sig, signature_fpw, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 921, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE( xrn_matrix );
    return final_ret;
}

int xrn_make_signature_symmetric_bytes( uint8_t * in_buff_bytes,
                                        uint64_t in_buff_length,
                                        xmonomial_key_t monomial_key,
                                        xrn_matrix_t * xrn_matrix,
                                        xsignature_sym_t * signature, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xhash_t hash;
    xnum_t rnd, proof, tmp, hint;
    int final_ret, ret;
    uint8_t constant_execution, force_linearity, check_sparcity;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL ) || ( xrn_matrix == NULL ) || ( signature == NULL ) ) {
        XPRINT_ERR( 922, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 923, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 924, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 925, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // check monomial key sparsity

    ret = xrn_check_sparsity( monomial_key.distance );
    if ( ret == XERR_SPARSE_MKEY ) {
        XPRINT_ERR( 926, XERR_SPARSE_MKEY_MSG );
        return ret;
    }

    // compute hash

    ret = xrn_make_hash_bytes( in_buff_bytes, in_buff_length, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 927, XERR_GENERAL_MSG );
        return ret;
    }

    // compute random number

    ret = xrn_initialize_true_rnd_num( settings.rnd_str, &rnd );
    if ( XSUCCESS != ret ) {
        XPRINT_ERR( 928, XERR_GENERAL_MSG );
        return ret;
    }

    hint = rnd;

    // compute a secret distance

    constant_execution = settings.const_exec_time;
    force_linearity = 0;
    check_sparcity = 1;
    xrn_matrix_traverse( xrn_matrix, &hint, &monomial_key.distance, &tmp, &constant_execution,
                         &force_linearity, &check_sparcity );

    // compute the proof

    xrn_matrix_traverse( xrn_matrix, &hash.value, &tmp, &proof, &constant_execution, &force_linearity,
                         &check_sparcity );

    // store the results

    signature->hint = hint;
    signature->proof = proof;

    return final_ret;

}

int xrn_check_signature_symmetric_bytes( uint8_t * in_buff_bytes,
                                         uint64_t in_buff_length,
                                         xmonomial_key_t monomial_key,
                                         xrn_matrix_t * xrn_matrix,
                                         xsignature_sym_t signature, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int error;
    xnum_t sig_comp, tmp;
    xhash_t hash;
    int final_ret, ret;
    uint8_t constant_execution, force_linearity, check_sparcity;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL ) || ( xrn_matrix == NULL ) ) {
        XPRINT_ERR( 943, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 944, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 945, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 946, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // check monomial key sparsity

    ret = xrn_check_sparsity( monomial_key.distance );
    if ( ret == XERR_SPARSE_MKEY ) {
        XPRINT_ERR( 947, XERR_SPARSE_MKEY_MSG );
        return ret;
    }

    // compute hash
    ret = xrn_make_hash_bytes( in_buff_bytes, in_buff_length, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 948, XERR_GENERAL_MSG );
        return ret;
    }

    // calculate distance between hash and proof

    constant_execution = settings.const_exec_time;
    force_linearity = 0;
    check_sparcity = 1;
    xrn_matrix_traverse( xrn_matrix, &signature.hint, &monomial_key.distance, &tmp, &constant_execution,
                         &force_linearity, &check_sparcity );

    // compute temporary number

    xrn_matrix_traverse( xrn_matrix, &hash.value, &tmp, &sig_comp, &constant_execution, &force_linearity,
                         &check_sparcity );

    // encrypt the hash

    XNUM_CMP( signature.proof, sig_comp, error );

    if ( error != 0 ) {
        XPRINT_NOT( 1 );
        ret = ( int ) XWAR_SIG;
    } else {
        XPRINT_NOT( 0 );
    }

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );

    return final_ret;

}

int xrn_check_signature_symmetric_bytes_wrapper( uint8_t * in_buff_bytes,
                                                 uint64_t in_buff_length,
                                                 FILE * monomial_key_fp,
                                                 FILE * xrn_matrix_fp,
                                                 FILE * signature_fp, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t *xrn_matrix;
    xmonomial_key_t mkey;
    xsignature_sym_t sig;
    int final_ret, ret;

    if ( ( in_buff_bytes == NULL ) || ( monomial_key_fp == NULL ) || ( xrn_matrix_fp == NULL )
         || ( signature_fp == NULL ) ) {
        XPRINT_ERR( 955, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 956, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // read signature
    ret = xrn_load_signature_sym( &sig, signature_fp, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 957, XERR_GENERAL_MSG );
        return ret;
    }

    // initialize variables

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 958, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // load xoron matrix
    ret = xrn_load_matrix( xrn_matrix_fp, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 959, XERR_GENERAL_MSG );
        return ret;
    }

    // load monomial key

    ret = xrn_load_monomial_key( &mkey, monomial_key_fp, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 960, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_check_signature_symmetric_bytes( in_buff_bytes, in_buff_length, mkey, xrn_matrix, sig, settings );

    XRN_FREE( xrn_matrix );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 961, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_make_hash_bytes( uint8_t * in, uint64_t len, xrn_matrix_t * xrn_matrix, xhash_t * hash,
                         xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint64_t block_i, i;
    xstate_t state_tmp;
    xstate_t state_internal;
    hash_load_variables_t load_variables;
    xnum_t init_vector;
    uint64_t state_size;
    int final_ret, ret;
    xrn_encoding_param_t enc_param;
    xrn_log_t xlog2;

    if ( ( hash == NULL ) || ( in == NULL ) || ( xrn_matrix == NULL ) ) {
        XPRINT_ERR( 985, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // initialize encoding decoding param

    ret = xrn_initialize_encoding_parameters( &enc_param, settings.encoding_settings.o_settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 986, XERR_GENERAL_MSG );
        return ret;
    }

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 987, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 988, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 989, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    state_size = ( uint64_t ) settings.state_size + 1;

    state_tmp.xnums = ( xnum_t * ) malloc( sizeof( xnum_t ) * state_size );
    if ( state_tmp.xnums == NULL ) {
        XPRINT_ERR( 990, XERR_NULL_MSG );
        return XERR_NULL;
    }

    state_internal.xnums = ( xnum_t * ) malloc( sizeof( xnum_t ) * state_size );
    if ( state_internal.xnums == NULL ) {
        XRN_FREE_XSTATE( state_tmp.xnums, settings.state_size );
        XPRINT_ERR( 991, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // Initialize variables

    for ( i = 0; i < sizeof( xnum_t ) - sizeof( uint64_t ); i++ ) {
        ( ( uint8_t * ) & init_vector )[i] = 0;
    }

    for ( i = 0; i < state_size; i++ ) {
        xrn_initialize_num( &state_internal.xnums[i] );
    }

    crypto_hash_init( &load_variables );

    // Perform hashing

    for ( block_i = 0; !load_variables.last_block; block_i++ ) {

        // generate a random state

        init_round_state( xrn_matrix, init_vector, block_i, &state_tmp, settings );

        // Update internal state

        for ( i = 0; i < state_size; i++ ) {
            X_XOR3( state_tmp.xnums[i], state_internal.xnums[i], state_internal.xnums[i] );
        }

        // Read the file

        ret =
            from_bytes_2_hash_block( in, ( int ) len, ( int ) block_i, &state_tmp, &load_variables,
                                     settings );

        final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
        if ( final_ret == XERR_GENERAL ) {
            XRN_FREE_XSTATE( state_tmp.xnums, settings.state_size );
            XRN_FREE_XSTATE( state_internal.xnums, settings.state_size );
            XPRINT_ERR( 992, XERR_GENERAL_MSG );
            return ret;
        }

        // Perform cross traverses on the input

        ret = xrn_cross_traverses( &state_tmp, xrn_matrix, &state_tmp, settings );

        final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
        if ( final_ret == XERR_GENERAL ) {
            XRN_FREE_XSTATE( state_tmp.xnums, settings.state_size );
            XRN_FREE_XSTATE( state_internal.xnums, settings.state_size );
            XPRINT_ERR( 994, XERR_GENERAL_MSG );
            return ret;
        }

        // Mix with the internal state

        for ( i = 0; i < state_size; i++ ) {
            X_XOR3( state_tmp.xnums[i], state_internal.xnums[i], state_internal.xnums[i] );
        }

    }

    xrn_compress_state( state_internal, &hash->value, settings );

    XRN_FREE_XSTATE( state_tmp.xnums, settings.state_size );
    XRN_FREE_XSTATE( state_internal.xnums, settings.state_size );

    return final_ret;

}

int xrn_make_hash_bytes_wrapper( uint8_t * in,
                                 uint64_t len,
                                 FILE * xrn_matrix_fp, FILE * hash_fp, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t *xrn_matrix;
    xhash_t hash;
    int final_ret, ret;

    if ( ( hash_fp == NULL ) || ( in == NULL ) || ( xrn_matrix_fp == NULL ) ) {
        XPRINT_ERR( 995, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 996, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 997, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fp, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 998, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_make_hash_bytes( in, len, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 999, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_dump_hash( hash, hash_fp, settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1000, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE( xrn_matrix );
    return final_ret;

}

int xrn_check_hash_bytes_wrapper( uint8_t * bytes, uint64_t length, FILE * input_hash_fpr,
                                  FILE * xrn_matrix_fpr, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int final_ret, ret;
    xhash_t hash;
    xrn_matrix_t *xrn_matrix;

    if ( ( bytes == NULL ) || ( input_hash_fpr == NULL ) || ( xrn_matrix_fpr == NULL ) ) {
        XPRINT_ERR( 1028, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1029, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    ret = xrn_load_hash( &hash, input_hash_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1030, XERR_GENERAL_MSG );
        return ret;
    }

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 1031, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1032, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_check_hash_bytes( bytes, length, hash, xrn_matrix, settings );

    XRN_FREE( xrn_matrix );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1033, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_check_hash_bytes( uint8_t * bytes, uint64_t length, xhash_t hash, xrn_matrix_t * xrn_matrix,
                          xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int final_ret, ret;
    int equal;
    xhash_t hash2;
    xrn_log_t xlog2;

    if ( ( bytes == NULL ) || ( xrn_matrix == NULL ) ) {
        XPRINT_ERR( 1034, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1035, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 1036, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 1037, XERR_GENERAL_MSG );
            return ret;
        }

    }

    ret = xrn_make_hash_bytes( bytes, length, xrn_matrix, &hash2, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1038, XERR_GENERAL_MSG );
        return ret;
    }

    XNUM_CMP( hash.value, hash2.value, equal );

    if ( equal == 0 ) {
        XPRINT_NOT( 0 );
        ret = XEQUAL;
    } else {
        XPRINT_NOT( 1 );
        ret = XNOT_EQUAL;
    }

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    return final_ret;

}

int xrn_decrypt_asymmetric_bytes_wrapper( uint8_t * in_buff_bytes,
                                          uint64_t in_buff_length,
                                          uint8_t * out_buff_bytes,
                                          uint64_t out_buff_length,
                                          uint64_t * num_decoded_bytes,
                                          FILE * xrn_matrix_fpr,
                                          FILE * monomial_key_fpr, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xmonomial_key_t monomial_key;
    xrn_matrix_t *xrn_matrix;
    int final_ret, ret;

    if ( ( in_buff_bytes == NULL ) || ( out_buff_bytes == NULL )
         || ( num_decoded_bytes == NULL ) || ( monomial_key_fpr == NULL )
         || ( xrn_matrix_fpr == NULL )
         ) {
        XPRINT_ERR( 1039, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1040, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 1041, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1042, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_load_monomial_key( &monomial_key, monomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1043, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_decrypt_asymmetric_bytes( in_buff_bytes, in_buff_length, out_buff_bytes, out_buff_length,
                                      num_decoded_bytes, xrn_matrix, monomial_key, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1044, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE( xrn_matrix );
    return final_ret;
}

int xrn_decrypt_asymmetric_bytes( uint8_t * in_buff_bytes,
                                  uint64_t in_buff_length,
                                  uint8_t * out_buff_bytes,
                                  uint64_t out_buff_length,
                                  uint64_t * num_decoded_bytes,
                                  xrn_matrix_t * xrn_matrix,
                                  xmonomial_key_t monomial_key, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xmonomial_key_t shared;
    xnum_t hint;
    int l;
    uint64_t in_index;
    xnum_t init_vector;
    xstate_t hidden_state;
    uint64_t state_size;
    xrn_encoding_tmp_param_t enc_param_tmp;
    xrn_encoding_param_t enc_param;
    int final_ret, ret;
    uint8_t constant_execution, force_linearity, check_sparcity;
    xrn_lib_xtype_t exp_type;
    xrn_lib_xtype_t type;
    uint8_t crc_bytes_header;
    uint8_t state_size_header;
    uint32_t reserved_0, reserved_1;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL ) || ( out_buff_bytes == NULL ) || ( xrn_matrix == NULL )
         || ( num_decoded_bytes == NULL ) ) {
        XPRINT_ERR( 1045, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;
    in_index = 0;

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 1046, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 1047, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 720, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // load header

    exp_type = c_asy_encryption;
    ret =
        xrn_load_header_bytes( in_buff_bytes, in_buff_length, &crc_bytes_header,
                               &type, exp_type,
                               &state_size_header, &in_index,
                               &reserved_0, &reserved_1, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 719, XERR_GENERAL_MSG );
        return ret;
    }

    settings.crc_bytes = crc_bytes_header;
    settings.state_size = state_size_header;

    constant_execution = settings.const_exec_time;
    force_linearity = 1;
    check_sparcity = 1;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 718, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // input checks

    ret = xrn_estimate_decryption_bytes_length( type, in_buff_length, &out_buff_length, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1057, XERR_GENERAL_MSG );
        return ret;
    }

    // read initialization vector 
    if ( ( uint64_t ) in_index + ( sizeof( xnum_t ) - sizeof( uint64_t ) ) > in_buff_length ) {
        XPRINT_ERR( 1058, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    for ( l = 0; l < ( sizeof( xnum_t ) - sizeof( uint64_t ) ); l++ ) {
        ( ( uint8_t * ) & init_vector )[l] = in_buff_bytes[in_index];
        in_index++;
    }

    // decode bytes

    ret =
        xrn_decode( &enc_param, ( uint8_t * ) & init_vector, ( uint8_t * ) & init_vector,
                    sizeof( xnum_t ) - sizeof( uint64_t ), &enc_param_tmp );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1059, XERR_VERSION_MSG );
        return XERR_VERSION;
    }

    // Read hint

    if ( ( uint64_t ) in_index + sizeof( xnum_t ) > in_buff_length ) {
        XPRINT_ERR( 1060, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    for ( l = 0; l < sizeof( xnum_t ); l++ ) {
        ( ( uint8_t * ) & hint )[l] = in_buff_bytes[in_index];
        in_index++;
    }

    // decode bytes

    ret =
        xrn_decode( &enc_param, ( uint8_t * ) & hint, ( uint8_t * ) & hint, sizeof( xnum_t ),
                    &enc_param_tmp );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1061, XERR_VERSION_MSG );
        return XERR_VERSION;
    }

    // Compute shared key

    ret =
        xrn_matrix_traverse( xrn_matrix, &hint, &monomial_key.distance, &shared.distance,
                             &constant_execution, &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1062, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_matrix_traverse( xrn_matrix, &hint, &shared.distance, &shared.distance, &constant_execution,
                             &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1063, XERR_GENERAL_MSG );
        return ret;
    }

    state_size = ( uint64_t ) settings.state_size + 1;
    hidden_state.xnums = ( xnum_t * ) malloc( sizeof( xnum_t ) * state_size );
    if ( NULL == hidden_state.xnums ) {
        XPRINT_ERR( 1064, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = expand_xnum( xrn_matrix, shared.distance, &hidden_state, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
        XPRINT_ERR( 1065, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        loop_dec_bytes( in_buff_bytes, in_buff_length, out_buff_bytes, out_buff_length,
                        ( uint64_t ) in_index, num_decoded_bytes, &hidden_state, xrn_matrix,
                        init_vector, enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
        XPRINT_ERR( 1066, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
    return final_ret;

}

int xrn_encrypt_asymmetric_bytes_wrapper( uint8_t * in_buff_bytes,
                                          uint64_t in_buff_length,
                                          uint8_t * out_buff_bytes,
                                          uint64_t out_buff_length,
                                          uint64_t * num_encoded_bytes,
                                          FILE * xrn_matrix_fpr,
                                          FILE * binomial_key_fpr, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xbinomial_key_t binomial_key;
    xrn_matrix_t *xrn_matrix;
    int final_ret, ret;

    if ( ( in_buff_bytes == NULL ) || ( out_buff_bytes == NULL ) || ( binomial_key_fpr == NULL )
         || ( xrn_matrix_fpr == NULL ) || ( num_encoded_bytes == NULL ) ) {
        XPRINT_ERR( 1091, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1092, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 1093, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1094, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_load_binomial_key( &binomial_key, binomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1095, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_encrypt_asymmetric_bytes( in_buff_bytes, in_buff_length, out_buff_bytes, out_buff_length,
                                      num_encoded_bytes, xrn_matrix, binomial_key, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1096, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE( xrn_matrix );
    return final_ret;

}

int xrn_encrypt_asymmetric_bytes( uint8_t * in_buff_bytes,
                                  uint64_t in_buff_length,
                                  uint8_t * out_buff_bytes,
                                  uint64_t out_buff_length,
                                  uint64_t * num_encoded_bytes,
                                  xrn_matrix_t * xrn_matrix,
                                  xbinomial_key_t binomial_key, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_lib_xtype_t type;
    xmonomial_key_t shared;
    xnum_t hint, xnum_rnd;
    uint64_t out_index, out_index_tmp, l;
    xnum_t init_vector;
    xstate_t hidden_state;
    uint64_t buff0_len;
    uint64_t state_size;
    int final_ret, ret;
    xrn_encoding_param_t enc_param;
    xrn_encoding_tmp_param_t enc_param_tmp;
    uint8_t constant_execution, force_linearity, check_sparcity;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL ) || ( out_buff_bytes == NULL )
         || ( xrn_matrix == NULL ) || ( num_encoded_bytes == NULL ) ) {
        XPRINT_ERR( 1097, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;
    constant_execution = settings.const_exec_time;
    force_linearity = 1;
    check_sparcity = 1;

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 1098, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 1099, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1100, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // dump headers

    type = c_asy_encryption;
    ret = xrn_dump_header_bytes( out_buff_bytes,
                                 out_buff_length,
                                 type,
                                 settings.crc_bytes, settings.state_size, &out_index, &enc_param, settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 743, XERR_GENERAL_MSG );
        return XERR_GENERAL;
    }

    // estimate the number of bytes required

    buff0_len = 0;
    ret = xrn_estimate_encryption_bytes_length( type, in_buff_length, &buff0_len, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 712, XERR_GENERAL_MSG );
        return ret;
    }

    if ( out_buff_length < buff0_len ) {
        XPRINT_ERR( 709, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    // Write initialization vector 

    ret = xrn_initialize_true_rnd_num( settings.rnd_str, &init_vector );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1107, XERR_GENERAL_MSG );
        return ret;
    }

    if ( out_index + sizeof( xnum_t ) - sizeof( uint64_t ) > out_buff_length ) {
        XPRINT_ERR( 1108, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    for ( l = 0; l < sizeof( xnum_t ) - sizeof( uint64_t ); l++ ) {
        out_buff_bytes[out_index] = ( ( uint8_t * ) & init_vector )[l];
        out_index++;
    }

    // encoding output bytes

    out_index_tmp = out_index - ( sizeof( xnum_t ) - sizeof( uint64_t ) );
    ret =
        xrn_encode( &enc_param, &out_buff_bytes[out_index_tmp], &out_buff_bytes[out_index_tmp],
                    sizeof( xnum_t ) - sizeof( uint64_t ), &enc_param_tmp );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1109, XERR_GENERAL_MSG );
        return ret;
    }

    // Compute hint
    ret = xrn_initialize_true_rnd_num( settings.rnd_str, &xnum_rnd );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1110, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_matrix_traverse( xrn_matrix, &binomial_key.start, &xnum_rnd, &hint, &constant_execution,
                             &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1111, XERR_GENERAL_MSG );
        return ret;
    }

    // Write hint

    if ( out_index + sizeof( xnum_t ) > out_buff_length ) {
        XPRINT_ERR( 1112, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    for ( l = 0; l < sizeof( xnum_t ); l++ ) {
        out_buff_bytes[out_index] = ( ( uint8_t * ) & hint )[l];
        out_index++;
    }

    // encoding output bytes

    out_index_tmp = out_index - sizeof( xnum_t );

    ret =
        xrn_encode( &enc_param, &out_buff_bytes[out_index_tmp], &out_buff_bytes[out_index_tmp],
                    sizeof( xnum_t ), &enc_param_tmp );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1113, XERR_GENERAL_MSG );
        return ret;
    }

    // Compute shared key

    ret =
        xrn_matrix_traverse( xrn_matrix, &binomial_key.end, &xnum_rnd, &shared.distance,
                             &constant_execution, &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1114, XERR_GENERAL_MSG );
        return ret;
    }

    force_linearity = 0;
    xrn_matrix_traverse( xrn_matrix, &hint, &shared.distance, &shared.distance, &constant_execution,
                         &force_linearity, &check_sparcity );
    force_linearity = 1;

    state_size = ( uint64_t ) settings.state_size + 1;
    hidden_state.xnums = ( xnum_t * ) malloc( sizeof( xnum_t ) * state_size );
    if ( NULL == hidden_state.xnums ) {
        XPRINT_ERR( 1115, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = expand_xnum( xrn_matrix, shared.distance, &hidden_state, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
        XPRINT_ERR( 1116, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        loop_enc_bytes( in_buff_bytes, in_buff_length, out_buff_bytes, out_buff_length, out_index,
                        num_encoded_bytes, &hidden_state, xrn_matrix, init_vector, enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
        XPRINT_ERR( 1117, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
    return final_ret;

}

int xrn_decrypt_symmetric_bytes_wrapper( uint8_t * in_buff_bytes,
                                         uint64_t in_buff_length,
                                         uint8_t * out_buff_bytes,
                                         uint64_t out_buff_length,
                                         uint64_t * num_decoded_bytes,
                                         FILE * xrn_matrix_fpr,
                                         FILE * monomial_key_fpr, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t *xrn_matrix;
    xmonomial_key_t monomial_key;
    int final_ret, ret;

    if ( ( in_buff_bytes == NULL ) || ( out_buff_bytes == NULL ) || ( monomial_key_fpr == NULL )
         || ( xrn_matrix_fpr == NULL ) || ( num_decoded_bytes == NULL ) ) {
        XPRINT_ERR( 1263, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1264, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 1265, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1266, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_load_monomial_key( &monomial_key, monomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1267, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_decrypt_symmetric_bytes( in_buff_bytes, in_buff_length, out_buff_bytes, out_buff_length,
                                     num_decoded_bytes, xrn_matrix, monomial_key, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1268, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE( xrn_matrix );
    return final_ret;

}

int xrn_decrypt_symmetric_bytes( uint8_t * in_buff_bytes,
                                 uint64_t in_buff_length,
                                 uint8_t * out_buff_bytes,
                                 uint64_t out_buff_length,
                                 uint64_t * num_decoded_bytes,
                                 xrn_matrix_t * xrn_matrix,
                                 xmonomial_key_t monomial_key, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xnum_t init_vector;
    uint64_t l, in_index;
    xstate_t hidden_state;
    uint64_t estimated_out_size;
    uint64_t state_size;
    int ret;
    int final_ret;
    xrn_encoding_param_t enc_param;
    xrn_encoding_tmp_param_t enc_param_tmp;
    xrn_lib_xtype_t exp_type;
    xrn_lib_xtype_t type;
    uint8_t crc_bytes_header;
    uint8_t state_size_header;
    uint32_t reserved_0, reserved_1;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL ) || ( out_buff_bytes == NULL ) || ( xrn_matrix == NULL )
         || ( num_decoded_bytes == NULL ) ) {
        XPRINT_ERR( 1269, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 1270, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 1271, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1048, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // load header

    exp_type = c_sym_encryption;
    ret =
        xrn_load_header_bytes( in_buff_bytes, in_buff_length, &crc_bytes_header,
                               &type, exp_type,
                               &state_size_header, &in_index,
                               &reserved_0, &reserved_1, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 692, XERR_GENERAL_MSG );
        return ret;
    }

    settings.crc_bytes = crc_bytes_header;
    settings.state_size = state_size_header;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1056, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // check monomial key sparsity

    ret = xrn_check_sparsity( monomial_key.distance );
    if ( ret == XERR_SPARSE_MKEY ) {
        XPRINT_ERR( 1274, XERR_SPARSE_MKEY_MSG );
        return ret;
    }

    estimated_out_size = 0;
    ret = xrn_estimate_decryption_bytes_length( type, in_buff_length, &estimated_out_size, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1282, XERR_GENERAL_MSG );
        return ret;
    }

    if ( out_buff_length < estimated_out_size ) {
        XPRINT_ERR( 1283, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    // read initialization vector 

    if ( in_index + sizeof( xnum_t ) - sizeof( uint64_t ) > in_buff_length ) {
        XPRINT_ERR( 1284, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    for ( l = 0; l < sizeof( xnum_t ) - sizeof( uint64_t ); l++ ) {
        ( ( uint8_t * ) & init_vector )[l] = in_buff_bytes[in_index];
        in_index++;
    }

    // decode bytes

    ret =
        xrn_decode( &enc_param, ( uint8_t * ) & init_vector, ( uint8_t * ) & init_vector,
                    sizeof( xnum_t ) - sizeof( uint64_t ), &enc_param_tmp );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1285, XERR_VERSION_MSG );
        return XERR_VERSION;
    }

    state_size = ( uint64_t ) settings.state_size + 1;
    hidden_state.xnums = ( xnum_t * ) malloc( sizeof( xnum_t ) * state_size );
    if ( NULL == hidden_state.xnums ) {
        XPRINT_ERR( 1286, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = expand_xnum( xrn_matrix, monomial_key.distance, &hidden_state, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
        XPRINT_ERR( 1287, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        loop_dec_bytes( in_buff_bytes, in_buff_length, out_buff_bytes, out_buff_length,
                        ( uint64_t ) in_index, num_decoded_bytes, &hidden_state, xrn_matrix,
                        init_vector, enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
        XPRINT_ERR( 1288, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );

    return final_ret;

}

int xrn_encrypt_symmetric_bytes_wrapper( uint8_t * in_buff_bytes,
                                         uint64_t in_buff_length,
                                         uint8_t * out_buff_bytes,
                                         uint64_t out_buff_length,
                                         uint64_t * num_encoded_bytes,
                                         FILE * xrn_matrix_fpr,
                                         FILE * monomial_key_fpr, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t *xrn_matrix;
    xmonomial_key_t monomial_key;
    int final_ret, ret;

    if ( ( in_buff_bytes == NULL ) || ( out_buff_bytes == NULL ) || ( num_encoded_bytes == NULL )
         || ( monomial_key_fpr == NULL ) || ( xrn_matrix_fpr == NULL )
         ) {
        XPRINT_ERR( 1295, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1296, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 1297, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1298, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_load_monomial_key( &monomial_key, monomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1299, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_encrypt_symmetric_bytes( in_buff_bytes, in_buff_length, out_buff_bytes, out_buff_length,
                                     num_encoded_bytes, xrn_matrix, monomial_key, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1300, XERR_GENERAL_MSG );
        return ret;

    }

    XRN_FREE( xrn_matrix );
    return final_ret;

}

int xrn_encrypt_symmetric_bytes( uint8_t * in_buff_bytes,
                                 uint64_t in_buff_length,
                                 uint8_t * out_buff_bytes,
                                 uint64_t out_buff_length,
                                 uint64_t * num_encoded_bytes,
                                 xrn_matrix_t * xrn_matrix,
                                 xmonomial_key_t monomial_key, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_lib_xtype_t type;
    xnum_t init_vector;
    uint64_t out_index, out_index_tmp, l;
    xstate_t hidden_state;
    uint64_t buff0_len;
    uint64_t state_size;
    int final_ret, ret;
    xrn_encoding_param_t enc_param;
    xrn_encoding_tmp_param_t enc_param_tmp;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL ) || ( out_buff_bytes == NULL ) || ( xrn_matrix == NULL )
         || ( num_encoded_bytes == NULL ) ) {
        XPRINT_ERR( 1301, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 1302, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 1303, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1304, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // dump headers

    type = c_sym_encryption;
    ret = xrn_dump_header_bytes( out_buff_bytes,
                                 out_buff_length,
                                 type,
                                 settings.crc_bytes, settings.state_size, &out_index, &enc_param, settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 717, XERR_GENERAL_MSG );
        return XERR_GENERAL;
    }

    // check monomial key sparsity

    ret = xrn_check_sparsity( monomial_key.distance );
    if ( ret == XERR_SPARSE_MKEY ) {
        XPRINT_ERR( 1306, XERR_SPARSE_MKEY_MSG );
        return ret;
    }

    buff0_len = 0;

    ret = xrn_estimate_encryption_bytes_length( type, in_buff_length, &buff0_len, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 832, XERR_GENERAL_MSG );
        return ret;
    }

    if ( out_buff_length < buff0_len ) {
        XPRINT_ERR( 1309, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    // Write initialization vector 

    ret = xrn_initialize_true_rnd_num( settings.rnd_str, &init_vector );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1312, XERR_GENERAL_MSG );
        return ret;
    }

    if ( out_index + sizeof( xnum_t ) - sizeof( uint64_t ) > out_buff_length ) {
        XPRINT_ERR( 1313, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    for ( l = 0; l < sizeof( xnum_t ) - sizeof( uint64_t ); l++ ) {
        out_buff_bytes[out_index] = ( ( uint8_t * ) & init_vector )[l];
        out_index++;
    }

    // encoding output bytes

    out_index_tmp = out_index - ( sizeof( xnum_t ) - sizeof( uint64_t ) );
    ret =
        xrn_encode( &enc_param, &out_buff_bytes[out_index_tmp], &out_buff_bytes[out_index_tmp],
                    sizeof( xnum_t ) - sizeof( uint64_t ), &enc_param_tmp );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1314, XERR_GENERAL_MSG );
        return ret;
    }

    state_size = ( uint64_t ) settings.state_size + 1;
    hidden_state.xnums = ( xnum_t * ) malloc( sizeof( xnum_t ) * state_size );
    if ( NULL == hidden_state.xnums ) {
        XPRINT_ERR( 1315, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = expand_xnum( xrn_matrix, monomial_key.distance, &hidden_state, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
        XPRINT_ERR( 1316, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        loop_enc_bytes( in_buff_bytes, in_buff_length, out_buff_bytes, out_buff_length, out_index,
                        num_encoded_bytes, &hidden_state, xrn_matrix, init_vector, enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
        XPRINT_ERR( 1317, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE_XSTATE( hidden_state.xnums, settings.state_size );
    return final_ret;

}

int xrn_check_ring_signature_bytes( uint8_t * in_buff_bytes,
                                    uint64_t in_buff_length,
                                    xring_signature_t ring_sig,
                                    xmonomial_key_t monomial_key,
                                    xrn_matrix_t * xrn_matrix,
                                    xbinomial_key_t * tx_binomial_key, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint64_t i, neq, found;
    xbinomial_key_t rx_binomial_key;
    xhash_t hash;
    xnum_t tmp, zero, proof0, proof1, proof_point;
    xmonomial_key_t shared_key;
    xstart_point_t start_point;
    int final_ret, ret, error0, error1, index_binomial_key;
    uint8_t constant_execution, force_linearity, check_sparcity;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL ) || ( tx_binomial_key == NULL ) || ( xrn_matrix == NULL ) ) {
        XPRINT_ERR( 1437, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;
    constant_execution = settings.const_exec_time;
    force_linearity = 1;
    check_sparcity = 1;

    // check ring signature size

    if ( ( ring_sig.ring_size < XRN_MIN_RING_SIG_SIZE ) || ( ring_sig.ring_size > XRN_MAX_RING_SIG_SIZE ) ) {
        XPRINT_ERR( 1438, XERR_RING_SIG_SIZE_MSG );
        return XERR_RING_SIG_SIZE;
    }

    xrn_initialize_num( &zero );

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 1439, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 1440, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1441, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // perform hash of the message file    

    ret = xrn_make_hash_bytes( in_buff_bytes, in_buff_length, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1442, XERR_GENERAL_MSG );
        return ret;
    }

    // check start points

    neq = 0;
    for ( i = 0; ( i < ring_sig.ring_size - 1 ) && ( !neq ); i++ ) {
        XNUM_CMP( ring_sig.binomial_keys[i + 1].start, ring_sig.binomial_keys[i].start, neq );

        if ( neq == 1 ) {

            XPRINT_ERR( 1443, XERR_STARTS_MSG );
            return XERR_STARTS;

        }

    }

    // regenerate binomial key

    start_point.start = ring_sig.binomial_keys[0].start;

    ret = xrn_make_binomial_key( xrn_matrix, start_point, monomial_key, &rx_binomial_key, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1444, XERR_GENERAL_MSG );
        return ret;
    }

    // get index of your binomial key

    found = 0;
    index_binomial_key = -1;

    for ( i = 0; ( i < ring_sig.ring_size ) && ( !found ); i++ ) {
        XNUM_CMP( rx_binomial_key.end, ring_sig.binomial_keys[i].end, neq );
        found = !neq;
        if ( found == 1 ) {
            index_binomial_key = ( int ) i;
        }

    }

    if ( index_binomial_key == -1 ) {
        ret = ( int ) XWAR_SIG;
        XPRINT_NOT( 1 );
        return ret;
    }

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );

    found = 0;

    // loop for all the binomial keys

    for ( i = 0; ( i < ring_sig.ring_size ) && ( !found ); i++ ) {

        if ( i != index_binomial_key ) {

            // compute shared key
            ret =
                xrn_exchange_monomial_key( xrn_matrix, rx_binomial_key, ring_sig.binomial_keys[i],
                                           monomial_key, &shared_key, settings );

            final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
            if ( final_ret == XERR_GENERAL ) {
                XPRINT_ERR( 1445, XERR_GENERAL_MSG );
                return ret;
            }

            X_XOR3( shared_key.distance, hash.value, tmp );

            // calculate proof point

            ret =
                xrn_matrix_traverse( xrn_matrix, &ring_sig.hint, &tmp, &proof_point, &constant_execution,
                                     &force_linearity, &check_sparcity );

            final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
            if ( final_ret == XERR_GENERAL ) {
                XPRINT_ERR( 1446, XERR_GENERAL_MSG );
                return ret;
            }

            // calculate first proof

            ret =
                xrn_matrix_traverse( xrn_matrix, &ring_sig.binomial_keys[i].end, &ring_sig.proof,
                                     &proof1, &constant_execution, &force_linearity, &check_sparcity );

            final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
            if ( final_ret == XERR_GENERAL ) {
                XPRINT_ERR( 1447, XERR_GENERAL_MSG );
                return ret;
            }

            // calculate second proof

            ret =
                xrn_matrix_traverse( xrn_matrix, &proof_point, &ring_sig.proof, &proof0,
                                     &constant_execution, &force_linearity, &check_sparcity );

            final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
            if ( final_ret == XERR_GENERAL ) {
                XPRINT_ERR( 1448, XERR_GENERAL_MSG );
                return ret;
            }

            XNUM_CMP( proof0, ring_sig.binomial_keys[i].end, error0 );
            XNUM_CMP( proof1, proof_point, error1 );

            if ( !( error0 && error1 ) ) {
                *tx_binomial_key = ring_sig.binomial_keys[i];
                found = 1;

            }

        }

    }

    if ( found == 0 ) {
        XPRINT_NOT( 1 );
        ret = ( int ) XWAR_SIG;
    } else {
        XPRINT_NOT( 0 );
    }

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );

    return final_ret;

}

int xrn_check_ring_signature_bytes_wrapper( uint8_t * in_buff_bytes,
                                            uint64_t in_buff_length,
                                            FILE * ring_signature_fpr,
                                            FILE * monomial_key_fpr,
                                            FILE * xrn_matrix_fpr,
                                            FILE * tx_binomial_key_fpw, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xmonomial_key_t mkey;
    xring_signature_t ring_sig;
    xrn_matrix_t *xrn_matrix;
    xbinomial_key_t bkey_tx;
    int final_ret, ret;

    if ( ( in_buff_bytes == NULL ) || ( ring_signature_fpr == NULL ) || ( monomial_key_fpr == NULL )
         || ( xrn_matrix_fpr == NULL ) || ( tx_binomial_key_fpw == NULL ) ) {
        XPRINT_ERR( 1461, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1462, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    // load monomial key

    ret = xrn_load_monomial_key( &mkey, monomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1463, XERR_GENERAL_MSG );
        return ret;
    }

    // load ring signature key

    ret = xrn_load_ring_signature( &ring_sig, ring_signature_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1464, XERR_GENERAL_MSG );
        return ret;
    }

    // check ring signature size

    if ( ( ring_sig.ring_size < XRN_MIN_RING_SIG_SIZE ) || ( ring_sig.ring_size > XRN_MAX_RING_SIG_SIZE ) ) {

        XPRINT_ERR( 1465, XERR_RING_SIG_SIZE_MSG );
        return XERR_RING_SIG_SIZE;
    }

    // get xoron matrix

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {

        XPRINT_ERR( 1466, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {

        // free xoron matrix

        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1467, XERR_GENERAL_MSG );
        return ret;
    }

    ret =
        xrn_check_ring_signature_bytes( in_buff_bytes, in_buff_length, ring_sig, mkey, xrn_matrix, &bkey_tx,
                                        settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );

    // free xoron matrix

    XRN_FREE( xrn_matrix );

    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1468, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_dump_binomial_key( bkey_tx, tx_binomial_key_fpw, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1469, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_make_ring_signature_bytes( uint8_t * in_buff_bytes,
                                   uint64_t in_buff_length,
                                   xbinomial_key_t * binomial_key_decoys,
                                   xmonomial_key_t monomial_key,
                                   xbinomial_key_t tx_binomial_key,
                                   xbinomial_key_t rx_binomial_key,
                                   xrn_matrix_t * xrn_matrix,
                                   uint16_t ndecoys,
                                   xring_signature_t * ring_signature, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xmonomial_key_t shared_key;
    xring_signature_t ring_sig;
    xhash_t hash;
    xnum_t hint, zero, tmp, proof, xnum_rnd;
    uint64_t i, j;
    int error, greater;
    int final_ret, ret, carry;
    uint8_t constant_execution, force_linearity, check_sparcity;
    xrn_log_t xlog2;

    if ( ( in_buff_bytes == NULL )
         || ( binomial_key_decoys == NULL ) || ( xrn_matrix == NULL )
         || ( ring_signature == NULL ) ) {
        XPRINT_ERR( 1479, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;
    constant_execution = settings.const_exec_time;
    force_linearity = 1;
    check_sparcity = 1;

    // check ring signature size

    if ( ( ndecoys + 2 < XRN_MIN_RING_SIG_SIZE ) || ( ndecoys + 2 > XRN_MAX_RING_SIG_SIZE ) ) {
        XPRINT_ERR( 1480, XERR_RING_SIG_SIZE_MSG );
        return XERR_RING_SIG_SIZE;
    }

    // check if xoron matrix is correct

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xrn_matrix );
    xlog = xlog2;

    if ( XERR_NOT_MATRIX == ret ) {
        XPRINT_ERR( 1481, XERR_NOT_MATRIX_MSG );
        return XERR_NOT_MATRIX;
    }

    // permute xoron matrix

    if ( ( ( ( uint32_t ) ret & 0x00000fff ) != XINFO_PERMUTED_MATRIX ) ) {
        ret = xrn_permute_matrix( xrn_matrix );
        if ( XSUCCESS != ret ) {
            XPRINT_ERR( 1482, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1483, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    ring_sig.ring_size = ( uint8_t ) ( ndecoys + 2 );

    // initialize a ring signature data structure

    for ( i = 0; i < ndecoys; i++ ) {

        ring_sig.binomial_keys[i] = binomial_key_decoys[i];

        // check for uncommon starts
        if ( i > 0 ) {
            j = i - 1;
            XNUM_CMP( ring_sig.binomial_keys[i].start, ring_sig.binomial_keys[j].start, error );
            if ( error != 0 ) {
                XPRINT_ERR( 1485, XERR_STARTS_MSG );
                return XERR_STARTS;
            }

        }

    }

    ring_sig.binomial_keys[ndecoys] = rx_binomial_key;

    // check for uncommon starts
    j = ( uint64_t ) ndecoys - 1;
    XNUM_CMP( ring_sig.binomial_keys[ndecoys].start, ring_sig.binomial_keys[j].start, error );
    if ( error != 0 ) {
        XPRINT_ERR( 1486, XERR_STARTS_MSG );
        return XERR_STARTS;
    }

    ring_sig.binomial_keys[ndecoys + 1] = tx_binomial_key;

    // check for uncommon starts
    j = ( uint64_t ) ndecoys + 1;
    XNUM_CMP( ring_sig.binomial_keys[j].start, ring_sig.binomial_keys[ndecoys].start, error );
    if ( error != 0 ) {
        XPRINT_ERR( 1487, XERR_STARTS_MSG );
        return XERR_STARTS;
    }

    // check for uncommon ends
    for ( i = 0; i < ndecoys + 2; i++ ) {
        for ( j = i + 1; j < ndecoys + 2; j++ ) {
            XNUM_CMP( ring_sig.binomial_keys[i].end, ring_sig.binomial_keys[j].end, error );
            if ( error == 0 ) {
                XPRINT_ERR( 603, XERR_ENDS_MSG );
                return XERR_ENDS;
            }

        }

    }

    // compute hash of the message

    xrn_initialize_num( &hash.value );
    ret = xrn_make_hash_bytes( in_buff_bytes, in_buff_length, xrn_matrix, &hash, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1488, XERR_GENERAL_MSG );
        return ret;
    }

    // generate common key

    xrn_initialize_num( &shared_key.distance );

    ret =
        xrn_exchange_monomial_key( xrn_matrix, tx_binomial_key, rx_binomial_key, monomial_key, &shared_key,
                                   settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1489, XERR_GENERAL_MSG );
        return ret;
    }

    // get random number
    ret = xrn_initialize_true_rnd_num( "", &xnum_rnd );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1490, XERR_GENERAL_MSG );
        return ret;
    }

    // compute hint point
    ret =
        xrn_matrix_traverse( xrn_matrix, &rx_binomial_key.start, &xnum_rnd, &hint, &constant_execution,
                             &force_linearity, &check_sparcity );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1491, XERR_GENERAL_MSG );
        return ret;
    }

    ring_sig.hint = hint;

    // calculate distance

    X_XOR3( shared_key.distance, hash.value, tmp );

    xrn_initialize_num( &zero );
    carry = xrn_add_nums( tmp, xnum_rnd, 0, &tmp );
    while ( carry == 1 ) {

        carry = xrn_add_nums( tmp, zero, 1, &tmp );

    }

    xrn_compare_greater_equal_nums( tmp, monomial_key.distance, &greater );

    // invert distance

    if ( greater == 1 ) {

        // calculate distance between the previous sum and monomial key
        xrn_subtract_nums( tmp, monomial_key.distance, &proof );

    } else {

        // calculate distance between the previous sum and monomial key
        xrn_subtract_nums( monomial_key.distance, tmp, &proof );

    }

    ring_sig.proof = proof;

    *ring_signature = ring_sig;

    return final_ret;

}

int xrn_make_ring_signature_bytes_wrapper( uint8_t * in_buff_bytes,
                                           uint64_t in_buff_length,
                                           FILE ** binomial_key_decoys_fpr,
                                           FILE * monomial_key_fpr,
                                           FILE * tx_binomial_key_fpr,
                                           FILE * rx_binomial_key_fpr,
                                           FILE * xrn_matrix_fpr,
                                           uint16_t ndecoys, FILE * signature_fpw,
                                           xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int i;
    xmonomial_key_t mkey;
    xbinomial_key_t rx_bk, tx_bk;
    xrn_matrix_t *xrn_matrix;
    xbinomial_key_t *binomial_keys;
    xring_signature_t ring_sig;
    int final_ret, ret;

    // check ring signature size

    if ( ( ndecoys + 2 < XRN_MIN_RING_SIG_SIZE ) || ( ndecoys + 2 > XRN_MAX_RING_SIG_SIZE ) ) {
        XPRINT_ERR( 1505, XERR_RING_SIG_SIZE_MSG );
        return XERR_RING_SIG_SIZE;
    }

    final_ret = XSUCCESS;

    // check for null pointers

    if ( ( xrn_matrix_fpr == NULL ) || ( monomial_key_fpr == NULL ) || ( binomial_key_decoys_fpr == NULL )
         || ( tx_binomial_key_fpr == NULL ) || ( rx_binomial_key_fpr == NULL ) || ( in_buff_bytes == NULL )
         || ( signature_fpw == NULL ) ) {
        XPRINT_ERR( 1506, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1507, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    for ( i = 0; i < ndecoys; i++ ) {
        if ( binomial_key_decoys_fpr[i] == NULL ) {
            XPRINT_ERR( 1508, XERR_NULL_MSG );
            return XERR_NULL;
        }

    }

    // load monomial key
    ret = xrn_load_monomial_key( &mkey, monomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1509, XERR_GENERAL_MSG );
        return ret;
    }

    // load rx binomial key

    ret = xrn_load_binomial_key( &rx_bk, rx_binomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1510, XERR_GENERAL_MSG );
        return ret;
    }

    // load tx binomial key

    ret = xrn_load_binomial_key( &tx_bk, tx_binomial_key_fpr, &settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1511, XERR_GENERAL_MSG );
        return ret;
    }

    // get xoron matrix

    xrn_matrix = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xrn_matrix == NULL ) {
        XPRINT_ERR( 1512, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xrn_matrix, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1513, XERR_GENERAL_MSG );
        return ret;
    }

    // load decoys

    binomial_keys = ( xbinomial_key_t * ) malloc( sizeof( xbinomial_key_t ) * ( ndecoys ) );
    if ( binomial_keys == NULL ) {
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1514, XERR_NULL_MSG );
        return XERR_NULL;
    }

    for ( i = 0; i < ndecoys; i++ ) {

        ret = xrn_load_binomial_key( &binomial_keys[i], binomial_key_decoys_fpr[i], &settings );

        if ( ( XSUCCESS != ret ) && ( ret != XWAR_VERSION ) ) {
            XRN_FREEN( binomial_keys, sizeof( xbinomial_key_t ) * ( ndecoys ) );
            XRN_FREE( xrn_matrix );

            XPRINT_ERR( 1515, XERR_GENERAL_MSG );
            return ret;
        }

    }

    // initialize a ring signature data structure

    ret =
        xrn_make_ring_signature_bytes( in_buff_bytes, in_buff_length, binomial_keys, mkey, tx_bk, rx_bk,
                                       xrn_matrix, ndecoys, &ring_sig, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {

        XRN_FREEN( binomial_keys, sizeof( xbinomial_key_t ) * ( ndecoys ) );
        XRN_FREE( xrn_matrix );
        XPRINT_ERR( 1516, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREEN( binomial_keys, sizeof( xbinomial_key_t ) * ( ndecoys ) );
    XRN_FREE( xrn_matrix );

    // dump ring signature
    ret = xrn_dump_ring_signature( ring_sig, 1, signature_fpw, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1517, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_estimate_encryption_bytes_length( xrn_lib_xtype_t type,
                                          uint64_t input_buff_length,
                                          uint64_t * output_buff_length, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint64_t nblocks;
    uint64_t plain_text_block_size;
    uint64_t block_size;
    uint64_t state_size;

    if ( output_buff_length == NULL ) {
        XPRINT_ERR( 1919, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( input_buff_length < 0 ) {
        XPRINT_ERR( 1920, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1921, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    state_size = ( uint64_t ) settings.state_size + 1;
    block_size = ( uint64_t ) ( state_size * sizeof( xnum_t ) );
    *output_buff_length = 0;

    if ( type == c_sym_encryption ) {

        plain_text_block_size = state_size * sizeof( xnum_t );
        nblocks = ( ( input_buff_length + settings.crc_bytes ) / plain_text_block_size ) + 1;
        *output_buff_length =
            ( nblocks * block_size + ( sizeof( xnum_t ) - sizeof( uint64_t ) ) +
              sizeof( xrn_crypto_lib_header_t ) );

    } else if ( type == c_asy_encryption ) {

        plain_text_block_size = state_size * sizeof( xnum_t );
        nblocks = ( ( input_buff_length + settings.crc_bytes ) / plain_text_block_size ) + 1;
        *output_buff_length =
            ( nblocks * block_size +
              ( sizeof( xnum_t ) - sizeof( uint64_t ) ) + sizeof( xnum_t ) +
              sizeof( xrn_crypto_lib_header_t ) );

    } else {

        XPRINT_ERR( 1922, XERR_TYPE_MSG );
        return XERR_TYPE;

    }

    return XSUCCESS;

}

int xrn_estimate_decryption_bytes_length( xrn_lib_xtype_t type,
                                          uint64_t input_buff_length,
                                          uint64_t * output_buff_length, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint64_t nblocks;
    uint64_t block_size;
    uint64_t state_size;

    if ( output_buff_length == NULL ) {
        XPRINT_ERR( 1923, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( input_buff_length < 0 ) {
        XPRINT_ERR( 1924, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1925, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    state_size = ( uint64_t ) settings.state_size + 1;
    block_size = ( uint64_t ) ( state_size * sizeof( xnum_t ) );

    if ( type == c_sym_encryption ) {

        nblocks = ( input_buff_length - ( ( sizeof( xnum_t ) - sizeof( uint64_t ) ) +
                                          sizeof( xrn_crypto_lib_header_t ) ) ) / block_size + 1;
        *output_buff_length = nblocks * block_size - settings.crc_bytes - 1;

    } else if ( type == c_asy_encryption ) {

        nblocks = ( input_buff_length - ( sizeof( xnum_t ) + ( sizeof( xnum_t ) - sizeof( uint64_t ) ) +
                                          sizeof( xrn_crypto_lib_header_t ) ) ) / block_size + 1;
        *output_buff_length = nblocks * block_size - settings.crc_bytes - 1;

    } else {

        XPRINT_ERR( 1926, XERR_TYPE_MSG );
        return XERR_TYPE;
    }

    return XSUCCESS;

}

int xrn_estimate_split_bytes_length( xrn_lib_xtype_t type,
                                     uint64_t input_buff_length,
                                     uint64_t * output_buff_challenge_length,
                                     uint64_t * output_buff_solution_length,
                                     xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint64_t nblocks;
    uint64_t plain_text_block_size;
    uint64_t state_size;
    uint64_t block_size_split_join;

    if ( ( output_buff_challenge_length == NULL ) || ( output_buff_solution_length == NULL ) ) {
        XPRINT_ERR( 1927, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( input_buff_length < 0 ) {
        XPRINT_ERR( 1928, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1929, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    state_size = ( uint64_t ) settings.state_size + 1;
    block_size_split_join = ( uint64_t ) state_size *sizeof( xnum_t
     );

    *output_buff_challenge_length = 0;
    *output_buff_solution_length = 0;

    plain_text_block_size = state_size * sizeof( xnum_t );
    nblocks = ( ( input_buff_length + settings.crc_bytes ) / plain_text_block_size ) + 1;

    if ( ( type == c_challenge ) || ( type == c_solution ) ) {

        *output_buff_challenge_length =
            nblocks * block_size_split_join + sizeof( uint64_t ) + sizeof( xrn_crypto_lib_header_t ) -
            sizeof( xnum_t );
        *output_buff_solution_length = ( uint64_t ) xrn_estimate_solution_block_bytes_length(  );

    } else {

        XPRINT_ERR( 1930, XERR_TYPE_MSG );
        return XERR_TYPE;
    }

    return XSUCCESS;
}

int xrn_estimate_join_bytes_length( uint64_t input_buff_challenge_length,
                                    uint64_t * output_buff_length, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint64_t nblocks;
    uint64_t block_bytes;
    uint64_t block_size;

    struct xrn_challenge_header_t {

        uint32_t magic_number;
        uint32_t version;
        uint32_t reserved_0;
        uint32_t reserved_1;
        uint8_t type;
        uint8_t state_size;
        uint8_t crc8;

    } header_challenge;

    if ( output_buff_length == NULL ) {
        XPRINT_ERR( 1931, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( input_buff_challenge_length < 0 ) {
        XPRINT_ERR( 1932, XERR_BUFF_MSG );
        return XERR_BUFF;
    }

    block_size = ( uint64_t ) ( settings.state_size + 1 ) * sizeof( xnum_t );

    nblocks =
        ( uint64_t ) ( ( ( input_buff_challenge_length + sizeof( xnum_t ) ) -
                         ( settings.crc_bytes + sizeof( header_challenge ) +
                           sizeof( uint64_t ) ) ) / block_size + 1 );

    block_bytes = nblocks * block_size;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1933, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    *output_buff_length = block_bytes;

    return XSUCCESS;

}

int xrn_estimate_solution_block_bytes_length(
 )
{
    XPRINT_DEB(  );

    return ( sizeof( xrn_crypto_lib_header_t ) + sizeof( xnum_t ) + sizeof( uint64_t ) );

}

int xrn_estimate_decrypted_block_bytes_length( xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1935, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    return ( int ) ( ( ( int ) settings.state_size + 1 ) * ( int ) sizeof( xnum_t ) -
                     ( int ) settings.crc_bytes - 1 );
}

int xrn_estimate_challenge_block_bytes_length( xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 1937, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    return ( int ) ( settings.state_size + 1 ) * ( int ) sizeof( xnum_t );

}

int xrn_estimate_encrypted_block_bytes_length( xrn_lib_xtype_t type, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int header_size;

    // check extra settings

    if ( XSUCCESS != check_crypto_extra_settings_value( settings ) ) {
        XPRINT_ERR( 615, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    if ( type == c_sym_encryption ) {

        header_size = ( int ) ( sizeof( xnum_t ) - sizeof( uint64_t ) + sizeof( xrn_crypto_lib_header_t ) );

    } else if ( type == c_asy_encryption ) {

        header_size =
            ( int ) ( 2 * sizeof( xnum_t ) - sizeof( uint64_t ) + sizeof( xrn_crypto_lib_header_t ) );

    } else if ( type == c_challenge ) {

        header_size = ( int ) ( sizeof( uint64_t ) + sizeof( xrn_crypto_lib_header_t ) );

    } else if ( type == c_challenge ) {

        header_size = ( int ) ( sizeof( uint64_t ) + sizeof( xrn_crypto_lib_header_t ) );

    } else {

        XPRINT_ERR( 1938, XERR_TYPE_MSG );
        return XERR_TYPE;
    }

    return header_size;

}

